Compare commits

..

No commits in common. "master" and "v0.1.0" have entirely different histories.

105 changed files with 1767 additions and 11887 deletions

View File

@ -1,93 +1,45 @@
project(librexy) project(librexy)
cmake_minimum_required(VERSION 3.0.2) cmake_minimum_required(VERSION 3.0.2)
include(GNUInstallDirs) include(GNUInstallDirs)
include(CMakeDependentOption)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS 1) set(librexy_VERSION_STRING "000010000L")
set(librexy_VERSION_STRING "000020000L")
set(librexy_VERSION_MAJOR 0) set(librexy_VERSION_MAJOR 0)
set(librexy_VERSION_MINOR 2) set(librexy_VERSION_MINOR 1)
set(librexy_VERSION_REVISION 0) set(librexy_VERSION_REVISION 0)
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include) set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
include_directories(BEFORE SYSTEM "${INCLUDE_PATH}") include_directories(BEFORE SYSTEM "${INCLUDE_PATH}")
#find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck)
#if(CMAKE_CXX_CPPCHECK)
# list(APPEND CMAKE_CXX_CPPCHECK "--enable=warning" "--inconclusive" "--force" "--inline-suppr")
#endif()
cmake_dependent_option(ENABLE_SHARED "Build shared library" ON "NOT BUILD_HEADER_ONLY" OFF) option(ENABLE_SHARED "Build shared library" ON)
cmake_dependent_option(ENABLE_SSO "Use small string optimization" ON "NOT BUILD_HEADER_ONLY" ON)
option(ENABLE_PROFILING "Enable asan" OFF) option(ENABLE_PROFILING "Enable asan" OFF)
option(BUILD_TESTS "Enable testing" OFF) option(BUILD_TESTS "Enable testing" OFF)
option(BUILD_HEADER_ONLY "Enable header only build" OFF)
mark_as_advanced(ENABLE_PROFILING) mark_as_advanced(ENABLE_PROFILING)
if(MSVC) set(SOURCE_LIST "src/filerd.cpp" "src/string.cpp" "src/binary.cpp" "src/static_string.cpp" "src/threadpool.cpp")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "") add_library(ensure OBJECT "src/ensure.cpp")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "") target_compile_options(ensure PRIVATE -Wall -Wextra -pedantic -std=c++17)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/out CACHE STRING "") if(ENABLE_SHARED)
endif() add_library(rexy SHARED ${SOURCE_LIST})
set_target_properties(rexy PROPERTIES SOVERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}.${librexy_VERSION_REVISION}")
set(LIBREXY_LIBFLAGS "-lrexy")
set(CMAKE_CXX_STANDARD 20) target_link_libraries(rexy "-lpthread")
set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/algorithm.tpp" "include/rexy/utility.hpp" "include/rexy/hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/expression.hpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp" "include/rexy/buffer.hpp" "include/rexy/buffer.tpp" "include/rexy/debug_print.hpp" "include/rexy/deferred.hpp" "include/rexy/enum_traits.hpp" "include/rexy/storage_for.hpp" "include/rexy/storage_for.tpp" "include/rexy/visitor.hpp" "include/rexy/string_view.hpp" "include/rexy/string_view.tpp" "include/rexy/format.hpp" "include/rexy/format.tpp" "include/rexy/list.hpp" "include/rexy/list.tpp")
if(BUILD_HEADER_ONLY)
set(LIBREXY_BUILT_LIBRARY_HEADERS "")
set(librexy_HEADER_ONLY_BUILD 1)
add_library(rexy INTERFACE)
set(LIBREXY_LIBFLAGS "")
else() else()
set(LIBREXY_BUILT_LIBRARY_HEADERS "include/rexy/filerd.hpp" "include/rexy/threadpool.hpp" "include/rexy/demangle.hpp") add_library(rexy STATIC ${SOURCE_LIST})
set(librexy_HEADER_ONLY_BUILD 0) set(LIBREXY_LIBFLAGS "-lrexy -lpthread")
set(SOURCE_LIST "src/filerd.cpp" "src/string.cpp" "src/string_view.cpp" "src/threadpool.cpp" "src/demangle.cpp") target_link_libraries(rexy "-lpthread")
if(ENABLE_SHARED)
add_library(rexy SHARED ${SOURCE_LIST})
set_target_properties(rexy PROPERTIES SOVERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}")
set(LIBREXY_LIBFLAGS "-lrexy")
target_link_libraries(rexy "-lpthread")
else()
add_library(rexy STATIC ${SOURCE_LIST})
set(LIBREXY_LIBFLAGS "-lrexy -lpthread")
target_link_libraries(rexy "-lpthread")
endif()
if(MSVC)
#make msvc update the __cplusplus macro to actually comply to c++ standard
target_compile_options(rexy PRIVATE "/Zc:__cplusplus")
else()
target_compile_options(rexy PRIVATE "-Wall" "-Wextra" "-pedantic")
endif()
set_target_properties(rexy PROPERTIES VERSION "${librexy_VERSION_MAJOR}.${librexy_VERSION_MINOR}.${librexy_VERSION_REVISION}")
if(ENABLE_SSO)
set(librexy_ENABLE_SSO 1)
else()
set(librexy_ENABLE_SSO 0)
endif()
if(ENABLE_PROFILING)
target_compile_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
endif()
endif() endif()
if(ENABLE_PROFILING)
target_compile_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
target_link_options(rexy PRIVATE -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls)
endif()
if(BUILD_TESTS) if(BUILD_TESTS)
add_library(ensure OBJECT "src/ensure.cpp")
if(MSVC)
target_compile_options(ensure PRIVATE "/Zc:__cplusplus")
else()
target_compile_options(ensure PRIVATE "-Wall" "-Wextra" "-pedantic")
endif()
enable_testing() enable_testing()
add_subdirectory(tests) add_subdirectory(tests)
endif() endif()
set(LIBREXY_PUBLIC_HEADERS "include/rexy/rexy.hpp" "include/rexy/algorithm.hpp" "include/rexy/utility.hpp" "include/rexy/basic_string_hash.hpp" "include/rexy/hash.hpp" "include/rexy/static_string_hash.hpp" "include/rexy/string_hash.hpp" "include/rexy/mpmc_queue.hpp" "include/rexy/mpmc_queue.tpp" "include/rexy/traits.hpp" "include/rexy/steal.hpp" "include/rexy/binary.hpp" "include/rexy/expression.hpp" "include/rexy/binary_base.hpp" "include/rexy/binary_base.tpp" "include/rexy/string_base.hpp" "include/rexy/string.hpp" "include/rexy/filerd.hpp" "include/rexy/string_base.tpp" "include/rexy/allocator.hpp" "include/rexy/meta.hpp")
target_compile_options(rexy PRIVATE -Wall -Wextra -pedantic -std=c++17)
install(TARGETS rexy install(TARGETS rexy
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
@ -97,11 +49,8 @@ install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
) )
install(FILES ${LIBREXY_PUBLIC_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/") install(FILES ${LIBREXY_PUBLIC_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/")
install(FILES ${LIBREXY_BUILT_LIBRARY_HEADERS} DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy/")
install(DIRECTORY "include/rexy/detail" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp") install(DIRECTORY "include/rexy/detail" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
install(DIRECTORY "include/rexy/cx" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp") install(DIRECTORY "include/rexy/cx" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
install(DIRECTORY "include/rexy/compat" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
install(DIRECTORY "include/rexy/concepts" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/rexy" FILES_MATCHING PATTERN "*.hpp" PATTERN "*.tpp")
configure_file( configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc.cmake.in" "${CMAKE_CURRENT_SOURCE_DIR}/pc/librexy.pc.cmake.in"

View File

@ -19,7 +19,11 @@
#ifndef REXY_ALGORITHM_HPP #ifndef REXY_ALGORITHM_HPP
#define REXY_ALGORITHM_HPP #define REXY_ALGORITHM_HPP
#include "utility.hpp" //swap
#include "rexy.hpp" #include "rexy.hpp"
#include <cstdint> //SIZE_MAX
#include <cstdlib> //size_t
#include <type_traits>
#include "detail/algorithm.hpp" #include "detail/algorithm.hpp"
@ -29,20 +33,84 @@ namespace rexy{
//right is one past the end of the list //right is one past the end of the list
template<class Iter, class Compare> template<class Iter, class Compare>
constexpr void quicksort(Iter left, Iter right, const Compare& cmp) constexpr void quicksort(Iter left, Iter right, const Compare& cmp)
noexcept(noexcept(detail::qs_partition(left, right, cmp))); noexcept(noexcept(detail::qs_partition(left, right, cmp)))
{
while(left < right){
auto real_right = right-1;
auto pivot = detail::qs_partition(left, real_right, cmp);
quicksort(left, pivot, cmp);
left = ++pivot;
}
}
//Requires Iterators to be LegacyRandomAccessIterators //Requires Iterators to be LegacyRandomAccessIterators
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter two_way_search(HIter hstart, HIter hend, NIter nstart, NIter nend); constexpr HIter two_way_search(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend){
size_t j = 0;
size_t i = 0;
size_t nlen = nend - nstart;
size_t hlen = hend - hstart;
auto [suffix, period] = detail::critical_factorization(nstart, nend);
if(detail::iter_compare(nstart, nstart + period, suffix)){
size_t memory = SIZE_MAX;
while(j <= hlen - nlen){
i = max(suffix, memory) + 1;
//right side
while(i < nlen && nstart[i] == hstart[i + j]){
++i;
}
if(i >= nlen){
i = suffix;
//left side
while(i > memory && nstart[i] == hstart[i + j]){
--i;
}
if(i <= memory){
return hstart + j;
}
j += period;
memory = nlen - period - 1;
}else{
j += (i - suffix);
memory = SIZE_MAX;
}
}
}else{
period = max(suffix + 1, nlen - suffix - 1) + 1;
j = 0;
while(j <= hlen - nlen){
i = suffix + 1;
//right side
while(i < nlen && nstart[i] == hstart[i + j]){
++i;
}
if(i >= nlen){
i = suffix;
//left side
while(i != SIZE_MAX && nstart[i] == hstart[i + j]){
--i;
}
if(i == SIZE_MAX){
return hstart + j;
}
j += period;
}else{
j += (i - suffix);
}
}
}
return hend;
}
//searcher for use with generic search wrappers //searcher for use with generic search wrappers
struct two_way_searcher{ struct two_way_searcher{
template<class HIter, class NIter> template<class HIter, class NIter>
constexpr HIter operator()(HIter hstart, HIter hend, NIter nstart, NIter nend)const; constexpr HIter operator()(const HIter& hstart, const HIter& hend, const NIter& nstart, const NIter& nend)const{
return two_way_search(hstart, hend, nstart, nend);
}
}; };
} }
#include "algorithm.tpp"
#endif #endif

View File

@ -1,108 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_ALGORITHM_TPP
#define REXY_ALGORITHM_TPP
#include <cstddef> //size_t
#include <limits> //numeric_limits
namespace rexy{
//Requires Iterators to be LegacyRandomAccessIterators
//right is one past the end of the list
template<class Iter, class Compare>
constexpr void quicksort(Iter left, Iter right, const Compare& cmp)
noexcept(noexcept(detail::qs_partition(left, right, cmp)))
{
while(left < right){
auto real_right = right-1;
auto pivot = detail::qs_partition(left, real_right, cmp);
quicksort(left, pivot, cmp);
left = ++pivot;
}
}
//Requires Iterators to be LegacyRandomAccessIterators
template<class HIter, class NIter>
constexpr HIter two_way_search(HIter hstart, HIter hend, NIter nstart, NIter nend){
std::size_t j = 0;
std::size_t i = 0;
std::size_t nlen = nend - nstart;
std::size_t hlen = hend - hstart;
auto [suffix, period] = detail::critical_factorization(nstart, nend);
if(detail::iter_compare(nstart, nstart + period, suffix)){
std::size_t memory = std::numeric_limits<std::size_t>::max();
while(j <= hlen - nlen){
i = max(suffix, memory) + 1;
//right side
while(i < nlen && nstart[i] == hstart[i + j]){
++i;
}
if(i >= nlen){
i = suffix;
//left side
while(i > memory && nstart[i] == hstart[i + j]){
--i;
}
if(i <= memory){
return hstart + j;
}
j += period;
memory = nlen - period - 1;
}else{
j += (i - suffix);
memory = std::numeric_limits<std::size_t>::max();
}
}
}else{
period = max(suffix + 1, nlen - suffix - 1) + 1;
j = 0;
while(j <= hlen - nlen){
i = suffix + 1;
//right side
while(i < nlen && nstart[i] == hstart[i + j]){
++i;
}
if(i >= nlen){
i = suffix;
//left side
while(i != std::numeric_limits<std::size_t>::max() && nstart[i] == hstart[i + j]){
--i;
}
if(i == std::numeric_limits<std::size_t>::max()){
return hstart + j;
}
j += period;
}else{
j += (i - suffix);
}
}
}
return hend;
}
template<class HIter, class NIter>
constexpr HIter two_way_searcher::operator()(HIter hstart, HIter hend, NIter nstart, NIter nend)const{
return two_way_search(hstart, hend, nstart, nend);
}
}
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,12 +19,77 @@
#ifndef REXY_DEFAULT_ALLOCATOR_HPP #ifndef REXY_DEFAULT_ALLOCATOR_HPP
#define REXY_DEFAULT_ALLOCATOR_HPP #define REXY_DEFAULT_ALLOCATOR_HPP
#include "compat/allocator.hpp" #include <cstdlib> //size_t
#include <type_traits> //true_type, false_type
#include <new>
#include <limits> //numeric_limits
#include <type_traits> //declval #include "rexy.hpp"
namespace rexy{ namespace rexy{
template<class T>
struct allocator
{
using pointer = T*;
using const_pointer = const T*;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using is_always_equal = std::true_type;
using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::false_type;
template<class U>
struct rebind{
using other = allocator<U>;
};
private:
constexpr bool has_overflow(size_type n)const{
return n > max_size();
}
public:
allocator(void) = default;
allocator(const allocator&) = default;
allocator(allocator&&) = default;
template<class U>
constexpr allocator(const allocator<U>&)noexcept{}
~allocator(void) = default;
pointer allocate(size_type n){
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
return reinterpret_cast<pointer>(::operator new(bytes));
}else{
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
}
}
void deallocate(pointer p, size_type n){
#if defined(__clang__) && !defined(__cpp_sized_deallocation)
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p);
}else{
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
}
#else
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p, bytes);
}else{
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
}
#endif
}
constexpr size_type max_size(void)const{
return std::numeric_limits<size_type>::max()/sizeof(T);
}
};
template<class T, class U> template<class T, class U>
constexpr bool operator==(const allocator<T>&, const allocator<U>&){ constexpr bool operator==(const allocator<T>&, const allocator<U>&){
return true; return true;
@ -33,14 +98,6 @@ namespace rexy{
constexpr bool operator!=(const allocator<T>&, const allocator<U>&){ constexpr bool operator!=(const allocator<T>&, const allocator<U>&){
return false; return false;
} }
template<REXY_ALLOCATOR_CONCEPT T>
struct is_nothrow_allocator{
static constexpr bool value = noexcept(std::declval<T>().allocate(0)) && noexcept(std::declval<T>().deallocate(nullptr, 0));
};
template<REXY_ALLOCATOR_CONCEPT T>
static constexpr bool is_nothrow_allocator_v = is_nothrow_allocator<T>::value;
} }
#endif #endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,17 +16,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_VISITOR_HPP #ifndef REXY_BASIC_STRING_HASH_HPP
#define REXY_VISITOR_HPP #define REXY_BASIC_STRING_HASH_HPP
#include "string_hash.hpp"
#include "string.hpp"
#include "rexy.hpp"
namespace rexy{ namespace rexy{
template<class... Funs> template<>
struct visitor : public Funs...{ struct hash<rexy::string> : public string_hash<rexy::string>{};
using Funs::operator()...;
};
template<class... Funs>
visitor(Funs...) -> visitor<Funs...>;
} }

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,14 +16,18 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_COMPAT_20_SOURCE_LOCATION_HPP #ifndef REXY_BINARY_HPP
#define REXY_COMPAT_20_SOURCE_LOCATION_HPP #define REXY_BINARY_HPP
#include <source_location> #include "binary_base.hpp"
#include "allocator.hpp"
#include "rexy.hpp"
namespace rexy::compat::cpp20{ namespace rexy{
using source_location = std::source_location; using binary = basic_binary<allocator<char>>;
extern template class basic_binary<allocator<char>>;
} }

View File

@ -0,0 +1,257 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_BINARY_BASE_HPP
#define REXY_BINARY_BASE_HPP
#include <cstdlib> //size_t
#include <utility> //move
#include <cstring> //memcpy
#include <cstddef> //ptrdiff_t
#include <type_traits>
#include <iterator> //reverse_iterator
#include "utility.hpp" //max
#include "steal.hpp"
#include "expression.hpp"
#include "traits.hpp"
#include "detail/string_appender.hpp"
#include "detail/hasallocator.hpp"
#include "rexy.hpp"
namespace rexy{
class binary_base
{
public:
using value_type = char;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
protected:
pointer m_data = nullptr;
size_type m_size = 0;
size_type m_cap = 0;
protected:
constexpr binary_base(void)noexcept = default;
constexpr binary_base(size_type len)noexcept;
constexpr binary_base(pointer data, size_type size)noexcept;
constexpr binary_base(pointer data, size_type size, size_type cap)noexcept;
constexpr binary_base(const binary_base& b)noexcept;
~binary_base(void)noexcept = default;
public:
constexpr pointer release(void)noexcept;
constexpr size_type size(void)const;
constexpr size_type capacity(void)const;
constexpr pointer get(void);
constexpr const_pointer get(void)const;
constexpr operator bool(void)const;
constexpr reference operator[](size_type i)noexcept;
constexpr const_reference operator[](size_type i)const noexcept;
constexpr iterator begin(void);
constexpr const_iterator begin(void)const;
constexpr iterator end(void);
constexpr const_iterator end(void)const;
constexpr const_iterator cbegin(void)const;
constexpr const_iterator cend(void)const;
constexpr reverse_iterator rbegin(void);
constexpr const_reverse_iterator rbegin(void)const;
constexpr reverse_iterator rend(void);
constexpr const_reverse_iterator rend(void)const;
constexpr const_reverse_iterator crbegin(void)const;
constexpr const_reverse_iterator crend(void)const;
};
template<class Allocator>
class basic_binary : protected detail::hasallocator<Allocator>, public binary_base
{
public:
using allocator_type = Allocator;
public:
constexpr basic_binary(void)noexcept;
constexpr basic_binary(rexy::steal<pointer> data, size_type size)noexcept;
constexpr basic_binary(rexy::steal<pointer> data, size_type cap, size_type size)noexcept;
constexpr basic_binary(rexy::steal<pointer> data)noexcept;
basic_binary(const_pointer data, size_type size)noexcept(noexcept(this->allocate(0)));
basic_binary(const_pointer data)noexcept(noexcept(this->allocate(0)));
basic_binary(const_pointer data, size_type size, size_type cap)noexcept(noexcept(this->allocate(0)));
explicit basic_binary(size_type size)noexcept(noexcept(this->allocate(0)));
basic_binary(size_type size, size_type cap)noexcept(noexcept(this->allocate(0)));
basic_binary(const basic_binary& b)noexcept(noexcept(this->allocate(0)));
constexpr basic_binary(basic_binary&& b)noexcept;
basic_binary(const binary_base& b)noexcept(noexcept(this->allocate(0)));
~basic_binary(void)noexcept(noexcept(this->deallocate(nullptr,0)));
basic_binary& operator=(const basic_binary& b)noexcept(noexcept(this->allocate(0)));
constexpr basic_binary& operator=(basic_binary&& b)noexcept;
basic_binary& operator=(const_pointer c)noexcept(noexcept(this->allocate(0)));
basic_binary& operator=(const binary_base& b)noexcept(noexcept(this->allocate(0)));
void reset(void)
noexcept(noexcept(this->deallocate(nullptr,0)));
void reset(pointer val, size_type cap, size_type size = 0)
noexcept(noexcept(this->deallocate(nullptr,0)));
bool resize(size_type newsize)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
void append(const_pointer data, size_type len)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
using detail::hasallocator<Allocator>::allocator;
private:
basic_binary& _copy_data(const_pointer data, size_type len)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
};
template<class Left, class Right>
class binary_cat_expr : public rexy::binary_expression<Left,Right>
{
private:
using left_t = std::decay_t<Left>;
using right_t = std::decay_t<Right>;
static_assert(std::is_same<typename left_t::value_type,typename right_t::value_type>::value);
public:
using value_type = typename left_t::value_type;
using size_type = decltype(typename left_t::size_type{0} + typename right_t::size_type{0});
using difference_type = decltype(typename left_t::difference_type{0} - typename right_t::difference_type{0});
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = pointer;
using const_iterator = const_pointer;
public:
using binary_expression<Left,Right>::binary_expression;
constexpr binary_cat_expr(const binary_cat_expr&) = default;
constexpr binary_cat_expr(binary_cat_expr&&) = default;
constexpr size_type size(void)const noexcept;
template<class Alloc>
operator basic_binary<Alloc>(void)
noexcept(std::is_nothrow_constructible<basic_binary<Alloc>, typename basic_binary<Alloc>::size_type>::value &&
std::is_nothrow_invocable<detail::string_appender<basic_binary<Alloc>>,decltype(*this)>::value);
};
class static_binary : public binary_base
{
public:
constexpr static_binary(void)noexcept = default;
constexpr static_binary(const_pointer str, size_type len)noexcept;
constexpr static_binary(const_pointer str)noexcept;
constexpr static_binary(const static_binary&)noexcept;
constexpr static_binary(static_binary&&)noexcept;
~static_binary(void)noexcept = default;
constexpr static_binary& operator=(const_pointer str)noexcept;
constexpr static_binary& operator=(const static_binary& str)noexcept;
constexpr static_binary& operator=(static_binary&& str)noexcept;
};
template<class Left, class Right>
binary_cat_expr(Left&&, Right&&) -> binary_cat_expr<Left&&,Right&&>;
template<class T>
struct is_binary{
static constexpr bool value = rexy::is_type<T,binary_base>::value || rexy::is_template_type<T,binary_cat_expr>::value;
};
template<class T>
struct is_concrete_binary{
static constexpr bool value = rexy::is_type<T,binary_base>::value;
};
namespace detail{
template<class... Ts>
using enable_if_binary = std::enable_if_t<(is_binary<Ts>::value && ...),int>;
template<class... Ts>
using enable_if_concrete_binary = std::enable_if_t<(is_concrete_binary<Ts>::value && ...),int>;
}
template<class Left, class Right, detail::enable_if_concrete_binary<Left,Right> = 0>
bool operator==(Left&& l, Right&& r)noexcept{
return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size());
}
template<class Left, class Right, detail::enable_if_concrete_binary<Left,Right> = 0>
bool operator!=(Left&& l, Right&& r)noexcept{
return !(std::forward<Left>(l) == std::forward<Right>(r));
}
template<class Left, class Right, detail::enable_if_binary<Left,Right> = 0>
auto operator+(Left&& l, Right&& r)
noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward<Left>(l), std::forward<Right>(r))))
{
return binary_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
}
template<class Left, detail::enable_if_binary<Left> = 0>
auto operator+(Left&& l, const char* c)
noexcept(noexcept(::new (nullptr) binary_cat_expr(std::forward<Left>(l), rexy::static_binary(c))))
{
return binary_cat_expr(std::forward<Left>(l), rexy::static_binary(c));
}
template<class Right, detail::enable_if_binary<Right> = 0>
auto operator+(const char* c, Right&& r)
noexcept(noexcept(::new (nullptr) binary_cat_expr(rexy::static_binary(c), std::forward<Right>(r))))
{
return binary_cat_expr(rexy::static_binary(c), std::forward<Right>(r));
}
template<class Left, class Right, detail::enable_if_concrete_binary<Left> = 0, detail::enable_if_binary<Right> = 0>
decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left,decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r));
}
template<class Left, detail::enable_if_concrete_binary<Left> = 0>
decltype(auto) operator+=(Left& l, const char* c)
noexcept(noexcept(l + c) && std::is_nothrow_assignable<Left, decltype(l + c)>::value)
{
return l = (l + c);
}
} //namespace rexy
#include "binary_base.tpp"
namespace{
constexpr inline rexy::static_binary operator"" _sb(const char* str, size_t len)noexcept{
return rexy::static_binary(str, len);
}
}
#ifdef REXY_STRING_HPP
#include "detail/binary_string_conv.hpp"
#endif
#endif

View File

@ -0,0 +1,313 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_BINARY_BASE_TPP
#define REXY_BINARY_BASE_TPP
#include <cstdlib> //size_t
#include <utility> //move
#include <cstring> //memcpy
#include <type_traits>
#include "utility.hpp" //max
#include "steal.hpp"
#include "detail/string_appender.hpp"
#define STOP_STRICT_ALIAS_WARNING(x) (x)
namespace rexy{
constexpr binary_base::binary_base(size_type len)noexcept:
m_cap(len){}
constexpr binary_base::binary_base(pointer data, size_type size)noexcept:
m_data(data), m_cap(size){}
constexpr binary_base::binary_base(pointer data, size_type size, size_type cap)noexcept:
m_data(data), m_size(size), m_cap(cap){}
constexpr binary_base::binary_base(const binary_base&)noexcept{}
constexpr auto binary_base::release(void)noexcept -> pointer{
return exchange(m_data, nullptr);
}
constexpr auto binary_base::size(void)const -> size_type{
return m_size;
}
constexpr auto binary_base::capacity(void)const -> size_type{
return m_cap;
}
constexpr auto binary_base::get(void) -> pointer{
return m_data;
}
constexpr auto binary_base::get(void)const -> const_pointer{
return m_data;
}
constexpr binary_base::operator bool(void)const{
return m_data;
}
constexpr auto binary_base::operator[](size_type i)noexcept -> reference{
return m_data[i];
}
constexpr auto binary_base::operator[](size_type i)const noexcept -> const_reference{
return m_data[i];
}
constexpr auto binary_base::begin(void) -> iterator{
return m_data;
}
constexpr auto binary_base::begin(void)const -> const_iterator{
return m_data;
}
constexpr auto binary_base::end(void) -> iterator{
return m_data + m_size;
}
constexpr auto binary_base::end(void)const -> const_iterator{
return m_data + m_size;
}
constexpr auto binary_base::cbegin(void)const -> const_iterator{
return m_data;
}
constexpr auto binary_base::cend(void)const -> const_iterator{
return m_data + m_size;
}
constexpr auto binary_base::rbegin(void) -> reverse_iterator{
return reverse_iterator(m_data + m_size);
}
constexpr auto binary_base::rbegin(void)const -> const_reverse_iterator{
return reverse_iterator(m_data + m_size);
}
constexpr auto binary_base::rend(void) -> reverse_iterator{
return reverse_iterator(m_data - 1);
}
constexpr auto binary_base::rend(void)const -> const_reverse_iterator{
return reverse_iterator(m_data - 1);
}
constexpr auto binary_base::crbegin(void)const -> const_reverse_iterator{
return rbegin();
}
constexpr auto binary_base::crend(void)const -> const_reverse_iterator{
return rend();
}
template<class Allocator>
constexpr basic_binary<Allocator>::basic_binary(void)noexcept{}
template<class Allocator>
constexpr basic_binary<Allocator>::basic_binary(rexy::steal<pointer> data)noexcept:
binary_base(data.value() ? strlen(data.value()) : 0)
{
m_data = data.value();
m_size = m_cap;
}
template<class Allocator>
constexpr basic_binary<Allocator>::basic_binary(rexy::steal<pointer> data, size_type size)noexcept:
binary_base(data.value(), size){}
template<class Allocator>
constexpr basic_binary<Allocator>::basic_binary(rexy::steal<pointer> data, size_type cap, size_type size)noexcept:
binary_base(data.value(), cap, size){}
template<class Allocator>
basic_binary<Allocator>::basic_binary(const_pointer data, size_type size)
noexcept(noexcept(this->allocate(0))):
binary_base(size ? this->allocate(size) : nullptr, size)
{
if(size)
memcpy(m_data, data, size);
}
template<class Allocator>
basic_binary<Allocator>::basic_binary(const_pointer data)
noexcept(noexcept(this->allocate(0))):
basic_binary(data ? this->allocate(strlen(data)) : nullptr, strlen(data))
{
if(data)
memcpy(m_data, data, m_cap);
}
template<class Allocator>
basic_binary<Allocator>::basic_binary(const_pointer data, size_type size, size_type cap)
noexcept(noexcept(this->allocate(0))):
binary_base(size ? this->allocate(size) : nullptr, size, cap)
{
if(size)
memcpy(m_data, data, size);
}
template<class Allocator>
basic_binary<Allocator>::basic_binary(size_type size)
noexcept(noexcept(this->allocate(0))):
binary_base(this->allocate(size), size){}
template<class Allocator>
basic_binary<Allocator>::basic_binary(size_type size, size_type cap)
noexcept(noexcept(this->allocate(0))):
binary_base(size ? this->allocate(size) : nullptr, size, cap){}
template<class Allocator>
basic_binary<Allocator>::basic_binary(const basic_binary& b)
noexcept(noexcept(this->allocate(0))):
binary_base(b.m_size ? this->allocate(b.m_size) : nullptr, b.m_size, b.m_size)
{
if(b.m_size)
memcpy(m_data, b.m_data, b.m_size);
}
template<class Allocator>
constexpr basic_binary<Allocator>::basic_binary(basic_binary&& b)noexcept:
binary_base(exchange(b.m_data, nullptr), b.m_size, b.m_cap){}
template<class Allocator>
basic_binary<Allocator>::basic_binary(const binary_base& b)
noexcept(noexcept(this->allocate(0))):
binary_base(b.size() ? this->allocate(b.size()) : nullptr, b.size(), b.size())
{
if(b.size())
memcpy(m_data, b.get(), b.size());
}
template<class Allocator>
basic_binary<Allocator>::~basic_binary(void)
noexcept(noexcept(this->deallocate(nullptr,0)))
{
this->deallocate(m_data, m_cap);
}
template<class Allocator>
basic_binary<Allocator>& basic_binary<Allocator>::operator=(const basic_binary& b)
noexcept(noexcept(this->allocate(0)))
{
return _copy_data(b.get(), b.size());
}
template<class Allocator>
constexpr basic_binary<Allocator>& basic_binary<Allocator>::operator=(basic_binary&& b)noexcept{
m_size = b.m_size;
m_cap = b.m_cap;
swap(m_data, b.m_data);
return *this;
}
template<class Allocator>
basic_binary<Allocator>& basic_binary<Allocator>::operator=(const_pointer c)
noexcept(noexcept(this->allocate(0)))
{
return _copy_data(c, strlen(c));
}
template<class Allocator>
basic_binary<Allocator>& basic_binary<Allocator>::operator=(const binary_base& b)
noexcept(noexcept(this->allocate(0)))
{
return _copy_data(b.get(), b.size());
}
template<class Allocator>
void basic_binary<Allocator>::reset(void)
noexcept(noexcept(this->deallocate(nullptr,0)))
{
this->deallocate(m_data, m_cap);
m_data = nullptr;
m_cap = m_size = 0;
}
template<class Allocator>
void basic_binary<Allocator>::reset(pointer val, size_type cap, size_type size)
noexcept(noexcept(this->deallocate(nullptr,0)))
{
this->deallocate(m_data, m_cap);
m_data = val;
m_cap = cap;
m_size = size;
}
template<class Allocator>
bool basic_binary<Allocator>::resize(size_type newsize)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)))
{
if(newsize < m_cap)
return false;
basic_binary<allocator_type> tmp(newsize);
if(!tmp)
return false;
memcpy(STOP_STRICT_ALIAS_WARNING(tmp).m_data, m_data, m_size);
swap(m_data, STOP_STRICT_ALIAS_WARNING(tmp).m_data);
m_cap = STOP_STRICT_ALIAS_WARNING(tmp).m_cap;
return true;
}
template<class Allocator>
void basic_binary<Allocator>::append(const_pointer data, size_type len)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)))
{
if(m_size + len > m_cap)
resize(max(m_cap*2, m_size+len));
memcpy(m_data+m_size, data, len);
m_size += len;
}
template<class Allocator>
basic_binary<Allocator>& basic_binary<Allocator>::_copy_data(const_pointer data, size_type len)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)))
{
if(!len)
return (*this = basic_binary(rexy::steal<pointer>(nullptr), 0, 0));
if(len <= m_size){
m_size = len;
memcpy(m_data, data, len);
return *this;
}
return (*this = basic_binary(data, len));
}
constexpr static_binary::static_binary(const_pointer str, size_type len)noexcept:
binary_base(const_cast<pointer>(str), len, len){}
constexpr static_binary::static_binary(const_pointer str)noexcept:
static_binary(str, strlen(str)){}
constexpr static_binary::static_binary(const static_binary& s)noexcept:
static_binary(s.get(), s.size()){}
constexpr static_binary::static_binary(static_binary&& s)noexcept:
static_binary(s.get(), s.size()){}
constexpr static_binary& static_binary::operator=(const_pointer str)noexcept{
m_data = const_cast<pointer>(str);
m_size = strlen(str);
m_cap = m_size;
return *this;
}
constexpr static_binary& static_binary::operator=(const static_binary& str)noexcept{
m_data = str.m_data;
m_size = str.m_size;
m_cap = str.m_cap;
return *this;
}
constexpr static_binary& static_binary::operator=(static_binary&& str)noexcept{
m_data = str.m_data;
m_size = str.m_size;
m_cap = str.m_cap;
return *this;
}
template<class Left, class Right>
constexpr auto binary_cat_expr<Left,Right>::size(void)const noexcept -> size_type{
return this->m_l.size() + this->m_r.size();
}
template<class Left, class Right>
template<class Alloc>
binary_cat_expr<Left,Right>::operator basic_binary<Alloc>(void)
noexcept(std::is_nothrow_constructible<basic_binary<Alloc>, typename basic_binary<Alloc>::size_type>::value &&
std::is_nothrow_invocable<detail::string_appender<basic_binary<Alloc>>,decltype(*this)>::value)
{
auto sz = size();
basic_binary<Alloc> ret(sz);
detail::string_appender<basic_binary<Alloc>> append(ret);
append(*this);
return ret;
}
}
#undef STOP_STRICT_ALIAS_WARNING
#endif

View File

@ -1,106 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_BUFFER_HPP
#define REXY_BUFFER_HPP
#include "allocator.hpp"
#include "detail/hasallocator.hpp"
#include <cstddef> //size_t, ptrdiff_t
#include <iterator> //reverse_iterator
#include "storage_for.hpp"
#include "compat/standard.hpp"
namespace rexy{
template<class T, class Allocator = allocator<T>>
class buffer : protected detail::hasallocator<Allocator>
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using allocator_type = Allocator;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
protected:
pointer m_data = nullptr;
size_type m_cap = 0;
size_type m_size = 0;
public:
constexpr buffer(void);
REXY_CPP20_CONSTEXPR buffer(const_pointer data, size_type length)noexcept(is_nothrow_allocator_v<Allocator>);
template<class Iter>
REXY_CPP20_CONSTEXPR buffer(const Iter& start, const Iter& last);
REXY_CPP20_CONSTEXPR buffer(size_type cap)noexcept(is_nothrow_allocator_v<Allocator>);
REXY_CPP20_CONSTEXPR buffer(const buffer& b)noexcept(is_nothrow_allocator_v<Allocator>);
constexpr buffer(buffer&& b)noexcept;
REXY_CPP20_CONSTEXPR ~buffer(void)noexcept(is_nothrow_allocator_v<Allocator>);
REXY_CPP20_CONSTEXPR buffer& operator=(const buffer& b)
noexcept(is_nothrow_allocator_v<Allocator>);
constexpr buffer& operator=(buffer&& b)noexcept;
constexpr pointer data(void);
constexpr const_pointer data(void)const;
REXY_CPP20_CONSTEXPR void resize(size_type new_cap);
constexpr void set_size(size_type size);
constexpr size_type cap(void)const;
constexpr const size_type& size(void)const;
constexpr size_type& size(void);
constexpr pointer release(void);
constexpr reference operator[](size_type i);
constexpr const_reference operator[](size_type i)const;
constexpr reference at(size_type i);
constexpr const_reference at(size_type i)const;
constexpr iterator begin(void);
constexpr const_iterator begin(void)const;
constexpr const_iterator cbegin(void)const;
constexpr iterator end(void);
constexpr const_iterator end(void)const;
constexpr const_iterator cend(void)const;
constexpr reverse_iterator rbegin(void);
constexpr const_reverse_iterator rbegin(void)const;
constexpr reverse_iterator rend(void);
constexpr const_reverse_iterator rend(void)const;
constexpr const_reverse_iterator crbegin(void)const;
constexpr const_reverse_iterator crend(void)const;
REXY_CPP20_CONSTEXPR void clear(void);
REXY_CPP20_CONSTEXPR void append(const_pointer p, size_type len);
};
}
#include "buffer.tpp"
#endif

View File

@ -1,220 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_BUFFER_TPP
#define REXY_BUFFER_TPP
#include <utility> //exchange, swap
#include <algorithm> //max
#include <memory> //construct_at
namespace rexy{
template<class T, class Allocator>
constexpr buffer<T,Allocator>::buffer(void){}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>::buffer(const_pointer data, size_type length)noexcept(is_nothrow_allocator_v<Allocator>):
m_data(this->allocate(sizeof(value_type) * length)),
m_cap(length),
m_size(length)
{
for(size_type i = 0;i < length;++i){
std::construct_at(m_data + i, data[i]);
}
}
template<class T, class Allocator>
template<class Iter>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>::buffer(const Iter& start, const Iter& last){
size_type count = 0;
for(auto it = start;it != last;++it){
++count;
}
m_data = this->allocate(sizeof(value_type) * count);
m_cap = count;
count = 0;
for(auto it = start;it != last;++it){
std::construct_at(m_data + count, *it);
++count;
}
m_size = count;
}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>::buffer(size_type cap)noexcept(is_nothrow_allocator_v<Allocator>):
m_data(this->allocate(sizeof(value_type) * cap)),
m_cap(cap),
m_size(0){}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>::buffer(const buffer& b)noexcept(is_nothrow_allocator_v<Allocator>):
m_data(this->allocate(sizeof(value_type) * b.m_cap)),
m_cap(b.m_cap),
m_size(b.m_size)
{
for(size_type i = 0;i < b.m_size;++i){
std::construct_at(m_data + i, b.m_data[i]);
}
}
template<class T, class Allocator>
constexpr buffer<T,Allocator>::buffer(buffer&& b)noexcept:
m_data(std::exchange(b.m_data, nullptr)),
m_cap(b.m_cap),
m_size(b.m_size){}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>::~buffer(void)noexcept(is_nothrow_allocator_v<Allocator>){
for(size_type i = 0;i < m_size;++i){
std::destroy_at(m_data + i);
}
this->deallocate(m_data, m_cap * sizeof(value_type));
}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR buffer<T,Allocator>& buffer<T,Allocator>::operator=(const buffer& b)
noexcept(is_nothrow_allocator_v<Allocator>)
{
return (*this = buffer(b));
}
template<class T, class Allocator>
constexpr buffer<T,Allocator>& buffer<T,Allocator>::operator=(buffer&& b)noexcept{
std::swap(m_data, b.m_data);
std::swap(m_size, b.m_size);
std::swap(m_cap, b.m_cap);
return *this;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::data(void) -> pointer{
return m_data;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::data(void)const -> const_pointer{
return m_data;
}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR void buffer<T,Allocator>::resize(size_type new_cap){
if(new_cap > m_cap){
buffer tmp(new_cap);
for(size_type i = 0;i < m_size;++i){
std::construct_at(tmp.m_data + i, std::move(m_data[i]));
}
std::swap(tmp.m_data, m_data);
}
m_cap = new_cap;
}
template<class T, class Allocator>
constexpr void buffer<T,Allocator>::set_size(size_type size){
m_size = size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::cap(void)const -> size_type{
return m_cap;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::size(void)const -> const size_type&{
return m_size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::size(void) -> size_type&{
return m_size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::release(void) -> pointer{
return std::exchange(m_data, nullptr);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::operator[](size_type i) -> reference{
return m_data[i];
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::operator[](size_type i)const -> const_reference{
return m_data[i];
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::at(size_type i) -> reference{
return m_data[i];
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::at(size_type i)const -> const_reference{
return m_data[i];
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::begin(void) -> iterator{
return m_data;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::begin(void)const -> const_iterator{
return m_data;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::cbegin(void)const -> const_iterator{
return m_data;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::end(void) -> iterator{
return m_data + m_size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::end(void)const -> const_iterator{
return m_data + m_size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::cend(void)const -> const_iterator{
return m_data + m_size;
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::rbegin(void) -> reverse_iterator{
return reverse_iterator(m_data + m_size);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::rbegin(void)const -> const_reverse_iterator{
return const_reverse_iterator(m_data + m_size);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::rend(void) -> reverse_iterator{
return reverse_iterator(m_data - 1);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::rend(void)const -> const_reverse_iterator{
return const_reverse_iterator(m_data - 1);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::crbegin(void)const -> const_reverse_iterator{
return const_reverse_iterator(m_data + m_size);
}
template<class T, class Allocator>
constexpr auto buffer<T,Allocator>::crend(void)const -> const_reverse_iterator{
return const_reverse_iterator(m_data - 1);
}
template<class T, class Allocator>
REXY_CPP20_CONSTEXPR void buffer<T,Allocator>::append(const_pointer p, size_type len){
if(len + m_size > m_cap){
buffer b(std::max(m_cap * 2, len + m_size));
b.append(m_data, m_size);
b.append(p, len);
*this = std::move(b);
}else{
for(size_type i = 0;i < len;++i){
std::construct_at(m_data + (m_size + i), p[i]);
}
m_size += len;
}
}
}
#endif

View File

@ -1,23 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if __cplusplus >= 202002L
#include "cpp20/allocator.hpp"
#else
#include "cpp17/allocator.hpp"
#endif

View File

@ -1,100 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP17_DEFAULT_ALLOCATOR_HPP
#define REXY_COMPAT_CPP17_DEFAULT_ALLOCATOR_HPP
#include <cstddef> //ptrdiff_t, size_t
#include <type_traits> //true_type, false_type
#include <new>
#include <limits> //numeric_limits
#include "../../rexy.hpp"
#define REXY_ALLOCATOR_CONCEPT class
namespace rexy{
template<class T>
struct allocator
{
using pointer = T*;
using const_pointer = const T*;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = std::size_t;
using difference_type = ptrdiff_t;
using is_always_equal = std::true_type;
using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::false_type;
template<class U>
struct rebind{
using other = allocator<U>;
};
private:
constexpr bool has_overflow(size_type n)const{
return n > max_size();
}
public:
allocator(void) = default;
allocator(const allocator&) = default;
allocator(allocator&&) = default;
template<class U>
constexpr allocator(const allocator<U>&)noexcept{}
~allocator(void) = default;
pointer allocate(size_type n){
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
return reinterpret_cast<pointer>(::operator new(bytes));
}else{
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
}
}
void deallocate(pointer p, size_type n){
#if !defined(__cpp_sized_deallocation)
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p);
}else{
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
}
#else //__cpp_sized_deallocation
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p, bytes);
}else{
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
}
#endif //__cpp_sized_deallocation
}
constexpr size_type max_size(void)const{
return std::numeric_limits<size_type>::max()/sizeof(T);
}
};
}
#endif

View File

@ -1,44 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP17_CX_STRING_HPP
#define REXY_COMPAT_CPP17_CX_STRING_HPP
#include "../../../string_base.hpp" //string_cat_expr
#include "../../../string_view.hpp" //string_view
#include <utility> //forward
#include <type_traits> //enable_if
namespace rexy::cx{
template<class Str1, class Str2, std::enable_if_t<is_cx_string<Str1,Str2>::value,int> = 0>
constexpr auto operator+(Str1&& l, Str2&& r)noexcept{
return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r));
}
template<class Str1, std::enable_if_t<is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(Str1&& l, const char* r)noexcept{
return string_cat_expr(std::forward<Str1>(l), rexy::basic_string_view<char>(r));
}
template<class Str1, std::enable_if_t<is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(const char* l, Str1&& r)noexcept{
return string_cat_expr(rexy::basic_string_view<char>(l), std::forward<Str1>(r));
}
}
#endif

View File

@ -1,107 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_17_SOURCE_LOCATION_HPP
#define REXY_COMPAT_17_SOURCE_LOCATION_HPP
#include <cstdint> //uint_least32_t
//clang bug: https://bugs.llvm.org/show_bug.cgi?id=48886
#if defined(__cpp_consteval) && !defined(__clang__)
#define CONSTEVAL consteval
#else
#define CONSTEVAL constexpr
#endif
namespace rexy::compat::cpp17{
class source_location
{
private:
const char* m_file;
const char* m_func;
uint_least32_t m_line;
uint_least32_t m_column;
public:
constexpr source_location(void)noexcept;
constexpr source_location(const source_location&);
constexpr source_location(source_location&&)noexcept;
constexpr uint_least32_t line(void)const noexcept;
constexpr uint_least32_t column(void)const noexcept;
constexpr const char* file_name(void)const noexcept;
constexpr const char* function_name(void)const noexcept;
public:
#if (defined(__clang__) && (__clang_major__ >= 9)) || (defined(_MSC_VER) && (_MSC_VER >= 1926))
static CONSTEVAL source_location current(uint_least32_t line = __builtin_LINE(),
uint_least32_t col = __builtin_COLUMN(),
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION())noexcept;
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
static CONSTEVAL source_location current(uint_least32_t line = __builtin_LINE(),
uint_least32_t col = 0,
const char* file = __builtin_FILE(),
const char* func = __builtin_FUNCTION())noexcept;
#else
static CONSTEVAL source_location current(uint_least32_t line = 0,
uint_least32_t col = 0,
const char* file = "unknown",
const char* func = "unknown")noexcept;
#endif
private:
constexpr source_location(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept;
};
constexpr source_location::source_location(void)noexcept:
source_location(0, 0, "unknown", "unknown"){}
constexpr source_location::source_location(const source_location& s):
source_location(s.m_line, s.m_column, s.m_file, s.m_func){}
constexpr source_location::source_location(source_location&& s)noexcept:
source_location(s.m_line, s.m_column, s.m_file, s.m_func){}
constexpr source_location::source_location(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept:
m_file(file),
m_func(func),
m_line(line),
m_column(col){}
constexpr uint_least32_t source_location::line(void)const noexcept{
return m_line;
}
constexpr uint_least32_t source_location::column(void)const noexcept{
return m_column;
}
constexpr const char* source_location::file_name(void)const noexcept{
return m_file;
}
constexpr const char* source_location::function_name(void)const noexcept{
return m_func;
}
CONSTEVAL source_location source_location::current(uint_least32_t line, uint_least32_t col, const char* file, const char* func)noexcept{
return source_location(line, col, file, func);
}
#undef CONSTEVAL
}
#endif

View File

@ -1,336 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP17_STRING_BASE_HPP
#define REXY_COMPAT_CPP17_STRING_BASE_HPP
#include "../../string_base.hpp"
#include <utility> //forward
#include <type_traits> //{false,true}_type, declval, enable_if, remove_reference, decay
#include <algorithm> //lexicographically_compare
#include "../../utility.hpp" //strlen, strncmp
#include "../../traits.hpp"
namespace rexy{
template<class Left, class Right>
class string_cat_expr;
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
class basic_string;
template<class Char>
class basic_string_view;
#define REXY_HAS_MEMFUN_WITH_RET(type, ret, fun, ...) \
template<class T> \
struct has_##fun##_f{ \
static std::false_type check(...); \
template<class type> \
static auto check(type* u) -> std::enable_if_t<std::is_convertible_v<decltype(std::declval<type>().fun(__VA_ARGS__)),ret>,std::true_type>; \
\
static constexpr bool value = decltype(check(std::declval<std::remove_reference_t<T>*>()))::value; \
}; \
template<class T> \
static constexpr bool has_##fun##_f_v = has_##fun##_f<T>::value
#define REXY_HAS_MEMOP_WITH_RET(type, ret, opname, op, ...) \
template<class T> \
struct has_##opname##_f{ \
static std::false_type check(...); \
template<class type> \
static auto check(type* u) -> std::enable_if_t<std::is_convertible_v<decltype(std::declval<type>().operator op(__VA_ARGS__)),ret>,std::true_type>; \
\
static constexpr bool value = decltype(check(std::declval<std::remove_reference_t<T>*>()))::value; \
}; \
template<class T> \
static constexpr bool has_##opname##_f_v = has_##opname##_f<T>::value
REXY_HAS_MEMFUN_WITH_RET(U, typename U::size_type, length);
REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_pointer, c_str);
REXY_HAS_MEMOP_WITH_RET(U, typename U::const_reference, indexop, [], 0);
REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, begin);
REXY_HAS_MEMFUN_WITH_RET(U, typename U::const_iterator, end);
#undef REXY_HAS_MEMFUN_WITH_RET
#undef REXY_HAS_MEMOP_WITH_RET
template<class T>
struct is_basic_string{
template<class Char, class Alloc>
static std::true_type check(const basic_string<Char,Alloc>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
};
template<class T>
struct is_basic_string_view{
template<class Char>
static std::true_type check(const basic_string_view<Char>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
};
template<class T>
struct is_basic_string_expr{
template<class Left, class Right>
static std::true_type check(const string_cat_expr<Left,Right>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<rexy::remove_cvref_t<T>*>()))::value;
};
template<class T>
struct is_string{
static constexpr bool value = (is_basic_string<T>::value || is_basic_string_view<T>::value) &&
(has_length_f_v<T> && has_c_str_f_v<T> && has_indexop_f_v<T> && has_begin_f_v<T> && has_end_f_v<T>);
};
template<class T>
static constexpr bool is_string_v = is_string<T>::value;
template<class... Ts>
struct are_strings{
static constexpr bool value = (is_string<Ts>::value && ...);
};
template<class... Ts>
static constexpr bool are_strings_v = are_strings<Ts...>::value;
template<class T>
struct is_string_expr{
static constexpr bool value = is_basic_string_expr<T>::value;
};
template<class T>
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
template<class... Ts>
struct are_string_expr{
static constexpr bool value = (is_string_expr<Ts>::value && ...);
};
template<class... Ts>
static constexpr bool are_string_expr_v = are_string_expr<Ts...>::value;
//Compare
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
constexpr bool operator==(const Str1& left, const Str2& right){
if(left.length() != right.length()){
return false;
}
return !rexy::strncmp(left.c_str(), right.c_str(), left.length()+1);
}
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator==(const Str1& left, typename std::decay_t<Str1>::const_pointer right){
if(right == nullptr){
return false;
}
const rexy::basic_string_view rstr(right);
if(rstr.length() != left.length()){
return false;
}
return !rexy::strncmp(left.c_str(), rstr.c_str(), left.length());
}
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, const Str1& right){
if(left == nullptr){
return false;
}
const rexy::basic_string_view lstr(left);
if(lstr.length() != right.length()){
return false;
}
return !rexy::strncmp(lstr.c_str(), right.c_str(), right.length());
}
template<class Str1, class Str2, std::enable_if_t<are_strings<Str1, Str2>::value,int> = 0>
constexpr bool operator!=(const Str1& left, const Str2& right)noexcept{
return !(left == right);
}
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator!=(const Str1& left, typename std::decay_t<Str1>::const_pointer right)noexcept{
return !(left == right);
}
template<class Str1, std::enable_if_t<are_strings<Str1>::value,int> = 0>
constexpr bool operator!=(typename std::decay_t<Str1>::const_pointer left, const Str1& right)noexcept{
return !(left == right);
}
template<class Str1, class Str2, std::enable_if_t<are_string<Str1,Str2>::value,int> = 0>
constexpr bool operator<(const Str1& left, const Str2& right)noexcept{
return std::lexicographical_compare(left.begin(), left.end(), right.begin(), right.end());
}
template<class Str1, class Str2, std::enable_if_t<are_string<Str1,Str2>::value,int> = 0>
constexpr bool operator<=(const Str1& left, const Str2& right)noexcept{
return !(right < left);
}
template<class Str1, class Str2, std::enable_if_t<are_string<Str1,Str2>::value,int> = 0>
constexpr bool operator>(const Str1& left, const Str2& right)noexcept{
return (right < left);
}
template<class Str1, class Str2, std::enable_if_t<are_string<Str1,Str2>::value,int> = 0>
constexpr bool operator>=(const Str1& left, const Str2& right)noexcept{
return !(left < right);
}
//String + string concat
template<class Left, class Right, std::enable_if_t<are_strings<Left, Right>::value,int> = 0>
constexpr auto operator+(Left&& l, Right&& r)
//uses deduction guide whereas std::is_nothrow_constructible couldn't
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(l), std::forward<Right>(r))))
{
return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
}
//String + char pointer
template<class Right, std::enable_if_t<is_string<Right>::value,int> = 0>
constexpr auto operator+(typename std::decay_t<Right>::const_pointer left, Right&& right)
noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::basic_string_view(left), std::forward<Right>(right))))
{
return string_cat_expr(rexy::basic_string_view(left), std::forward<Right>(right));
}
//Char pointer + string
template<class Left, std::enable_if_t<is_string<Left>::value,int> = 0>
constexpr auto operator+(Left&& left, typename std::decay_t<Left>::const_pointer right)
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(left), rexy::basic_string_view(right))))
{
return rexy::string_cat_expr(std::forward<Left>(left), rexy::basic_string_view(right));
}
//String + expr concat
template<class Left, class Right, std::enable_if_t<is_string<Left>::value && is_string_expr<Right>::value,int> = 0>
constexpr auto operator+(Left&& left, Right&& right){
return string_cat_expr(std::forward<Left>(left), std::forward<Right>(right));
}
//Expr + string
template<class Left, class Right, std::enable_if_t<is_string_expr<Left>::value && is_string<Right>::value,int> = 0>
constexpr auto operator+(Left&& left, Right&& right){
return string_cat_expr(std::forward<Left>(left), std::forward<Right>(right));
}
//Expr + expr
template<class Left, class Right, std::enable_if_t<are_string_expr<Left,Right>::value,int> = 0>
constexpr auto operator+(Left&& left, Right&& right){
return string_cat_expr(std::forward<Left>(left), std::forward<Right>(right));
}
//Expr + char pointer
template<class Left, std::enable_if_t<is_string_expr<Left>::value,int> = 0>
constexpr auto operator+(Left&& left, typename std::decay_t<Left>::const_pointer right){
return string_cat_expr(std::forward<Left>(left), rexy::basic_string_view(right));
}
//char pointer + Expr
template<class Right, std::enable_if_t<is_string_expr<Right>::value,int> = 0>
constexpr auto operator+(typename std::decay_t<Right>::const_pointer left, Right&& right){
return string_cat_expr(rexy::basic_string_view(left), std::forward<Right>(right));
}
//String concat assignment
template<class Left, class Right, std::enable_if_t<are_strings<Left,Right>::value,int> = 0>
decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left, decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r));
}
template<class Left, class Right, std::enable_if_t<is_string<Left>::value && is_string_expr<Right>::value,int> = 0>
decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left, decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r));
}
template<class Left, std::enable_if_t<is_string<Left>::value, int> = 0>
decltype(auto) operator+=(Left& l, typename std::decay_t<Left>::const_pointer r)
noexcept(noexcept(l + r) && std::is_nothrow_assignable<Left, decltype(l + r)>::value)
{
return l = (l + r);
}
template<class T, class Char, std::enable_if_t<is_string<T>::value, int> = 0>
constexpr std::size_t find_first_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
for(auto it = t.cbegin() + start;it != t.cend();++it){
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
return it - t.cbegin();
}
}
}
return rexy::npos;
}
template<class T, class Char, std::enable_if_t<is_string<T>::value, int> = 0>
constexpr std::size_t find_first_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
for(auto it = t.cbegin() + start;it != t.cend();++it){
bool found = false;
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
found = true;
break;
}
}
if(!found){
return it - t.cbegin();
}
}
return rexy::npos;
}
template<class T, class Char, std::enable_if_t<is_string<T>::value, int> = 0>
constexpr std::size_t find_last_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
const auto b = t.cend() - 1;
const auto e = t.cbegin() - 1 - start;
for(auto it = b;it != e;--it){
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
return it - t.cbegin();
}
}
}
return rexy::npos;
}
template<class T, class Char, std::enable_if_t<is_string<T>::value, int> = 0>
constexpr std::size_t find_last_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
const auto b = t.cend() - 1;
const auto e = t.cbegin() - 1 - start;
for(auto it = b;it != e;--it){
bool found = false;
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
found = true;
break;
}
}
if(!found){
return it - t.cbegin();
}
}
return rexy::npos;
}
}
#endif

View File

@ -1,35 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_17_TO_ADDRESS_HPP
#define REXY_COMPAT_17_TO_ADDRESS_HPP
namespace rexy::compat::cpp17{
template<class T>
constexpr T* to_address(T* p)noexcept{
return p;
}
template<class Ptr>
constexpr auto to_address(const Ptr& p)noexcept{
return to_address(p.operator->());
}
}
#endif

View File

@ -1,73 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP17_TRAITS_HPP
#define REXY_COMPAT_CPP17_TRAITS_HPP
namespace rexy{
template<class T>
struct remove_volatile{
using type = T;
};
template<class T>
struct remove_volatile<volatile T>{
using type = T;
};
template<class T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<class T>
struct remove_const{
using type = T;
};
template<class T>
struct remove_const<const T>{
using type = T;
};
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
struct remove_cv{
using type = remove_volatile_t<remove_const_t<T>>;
};
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
template<class T>
struct remove_reference{
using type = T;
};
template<class T>
struct remove_reference<T&>{
using type = T;
};
template<class T>
struct remove_reference<T&&>{
using type = T;
};
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template<class T>
struct remove_cvref{
using type = remove_cv_t<remove_reference_t<T>>;
};
template<class T>
using remove_cvref_t = typename remove_cvref<T>::type;
}
#endif

View File

@ -1,139 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP20_DEFAULT_ALLOCATOR_HPP
#define REXY_COMPAT_CPP20_DEFAULT_ALLOCATOR_HPP
#include <cstddef> //ptrdiff_t, size_t
#include <type_traits> //true_type, false_type
#include <new>
#include <limits> //numeric_limits
#include <memory> //allocator
#ifdef __cpp_concepts
#include <concepts> //convertible_to
template<class T>
concept Allocator = requires(T a, typename T::size_type sz, typename T::pointer pa){
typename T::value_type;
typename T::size_type;
typename T::pointer;
typename T::const_pointer;
{a.allocate(sz)} -> std::convertible_to<typename T::pointer>;
{a.deallocate(pa, sz)};
};
#define REXY_ALLOCATOR_CONCEPT Allocator
#else //__cpp_concepts
#define REXY_ALLOCATOR_CONCEPT class
#endif // __cpp_concepts
#include "../../rexy.hpp"
#include "../if_consteval.hpp"
namespace rexy{
template<class T>
struct allocator
{
using pointer = T*;
using const_pointer = const T*;
using void_pointer = void*;
using const_void_pointer = const void*;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using is_always_equal = std::true_type;
using propagate_on_container_copy_assignment = std::false_type;
using propagate_on_container_move_assignment = std::false_type;
using propagate_on_container_swap = std::false_type;
template<class U>
struct rebind{
using other = allocator<U>;
};
private:
constexpr bool has_overflow(size_type n)const{
return n > max_size();
}
public:
constexpr allocator(void) = default;
constexpr allocator(const allocator&) = default;
constexpr allocator(allocator&&) = default;
template<class U>
constexpr allocator(const allocator<U>&)noexcept{}
constexpr ~allocator(void) = default;
//'::operator new' is never a constexpr call as of C++23. However, 'std::allocator::allocate' *is* transiently constexpr as of C++20,
//even though it directly calls '::operator new' as is stated in the standard. Therefore, when evaluating this call with support for
//'if consteval', we can use the 'std::allocator::allocate' constexpr-ness when this is in a constant evaluation context.
constexpr pointer allocate(size_type n){
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
REXY_if_consteval{
std::allocator<value_type> a;
const size_type num_items = n / sizeof(value_type);
return a.allocate(num_items);
}else{
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
return reinterpret_cast<pointer>(::operator new(bytes));
}else{
return reinterpret_cast<pointer>(::operator new(bytes, static_cast<std::align_val_t>(alignof(T))));
}
} //if consteval
}
constexpr void deallocate(pointer p, size_type n){
REXY_if_consteval{
std::allocator<value_type> a;
const size_type num_items = n / sizeof(value_type);
return a.deallocate(p, num_items);
}else{
#if !defined(__cpp_sized_deallocation)
//clang does not enable ::operator delete(void* ptr, std::size_t sz) by default for some reason
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p);
}else{
::operator delete(p, static_cast<std::align_val_t>(alignof(T)));
}
#else //__cpp_sized_deallocation
size_type bytes = has_overflow(n) ? std::numeric_limits<size_type>::max() : n*sizeof(T);
if constexpr(alignof(T) <= __STDCPP_DEFAULT_NEW_ALIGNMENT__){
::operator delete(p, bytes);
}else{
::operator delete(p, bytes, static_cast<std::align_val_t>(alignof(T)));
}
#endif //__cpp_sized_deallocation
} //if consteval
}
constexpr size_type max_size(void)const{
return std::numeric_limits<size_type>::max()/sizeof(T);
}
};
}
#endif

View File

@ -1,46 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP20_CX_STRING_HPP
#define REXY_COMPAT_CPP20_CX_STRING_HPP
#include "../../../string_base.hpp" //string_cat_expr
#include "../../../string_view.hpp" //string_view
#include <utility> //forward
namespace rexy{
template<class T>
concept CxString = cx::is_cx_string<T>::value;
}
namespace rexy::cx{
template<CxString Str1, CxString Str2>
constexpr auto operator+(Str1&& l, Str2&& r)noexcept{
return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r));
}
template<CxString Str1>
constexpr auto operator+(Str1&& l, const char* r)noexcept{
return string_cat_expr(std::forward<Str1>(l), rexy::basic_string_view<char>(r));
}
template<CxString Str1>
constexpr auto operator+(const char* l, Str1&& r)noexcept{
return string_cat_expr(rexy::basic_string_view<char>(l), std::forward<Str1>(r));
}
}
#endif

View File

@ -1,257 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP20_STRING_BASE_HPP
#define REXY_COMPAT_CPP20_STRING_BASE_HPP
#include "../../string_base.hpp"
#include <utility> //forward
#include <type_traits> //decay, is_nothrow_assignable
#include <algorithm> //lexicographically_compare_three_way
#include "../../utility.hpp" //strlen, strncmp
namespace rexy{
template<class Left, class Right>
class string_cat_expr;
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
class basic_string;
template<class Char>
class basic_string_view;
template<class T>
struct is_basic_string{
template<class Char, class Alloc>
static std::true_type check(const basic_string<Char,Alloc>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
};
template<class T>
struct is_basic_string_view{
template<class Char>
static std::true_type check(const basic_string_view<Char>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
};
template<class T>
struct is_basic_string_expr{
template<class Left, class Right>
static std::true_type check(const string_cat_expr<Left,Right>*);
static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>*>()))::value;
};
template<class T>
concept BasicString = requires(const T& a){
requires(is_basic_string<T>::value || is_basic_string_view<T>::value);
{std::as_const(a).length()} -> std::convertible_to<typename std::decay_t<T>::size_type>;
{std::as_const(a).c_str()} -> std::convertible_to<typename std::decay_t<T>::const_pointer>;
{std::as_const(a)[0]} -> std::convertible_to<typename std::decay_t<T>::const_reference>;
{std::as_const(a).begin()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
{std::as_const(a).end()} -> std::convertible_to<typename std::decay_t<T>::const_iterator>;
};
template<class T>
concept StringExpr = is_basic_string_expr<T>::value;
template<class T>
concept String = BasicString<T> || StringExpr<T>;
template<class T>
struct is_string{
static constexpr bool value = BasicString<T>;
};
template<class T>
static constexpr bool is_string_v = is_string<T>::value;
template<class T>
struct is_string_expr{
static constexpr bool value = StringExpr<T>;
};
template<class T>
static constexpr bool is_string_expr_v = is_string_expr<T>::value;
//Compare
template<BasicString Str1, BasicString Str2>
constexpr bool operator==(const Str1& left, const Str2& right){
if(left.length() != right.length()){
return false;
}
return !rexy::strncmp(left.c_str(), right.c_str(), left.length()+1);
}
template<BasicString Str1>
constexpr bool operator==(const Str1& left, typename std::decay_t<Str1>::const_pointer right)noexcept{
if(right == nullptr){
return false;
}
const rexy::basic_string_view rstr(right);
if(rstr.length() != left.length()){
return false;
}
return !rexy::strncmp(left.c_str(), rstr.c_str(), left.length());
}
template<BasicString Str1>
constexpr bool operator==(typename std::decay_t<Str1>::const_pointer left, const Str1& right)noexcept{
if(left == nullptr){
return false;
}
const rexy::basic_string_view lstr(left);
if(lstr.length() != right.length()){
return false;
}
return !rexy::strncmp(lstr.c_str(), right.c_str(), right.length());
}
template<BasicString Str1, BasicString Str2>
constexpr bool operator!=(const Str1& left, const Str2& right)noexcept{
return !(left == right);
}
template<BasicString Str1>
constexpr bool operator!=(const Str1& left, typename std::decay_t<Str1>::const_pointer right)noexcept{
return !(left == right);
}
template<BasicString Str1>
constexpr bool operator!=(typename std::decay_t<Str1>::const_pointer left, const Str1& right)noexcept{
return !(left == right);
}
template<BasicString Str1, BasicString Str2>
constexpr auto operator<=>(const Str1& left, const Str2& right)noexcept{
return std::lexicographical_compare_three_way(left.begin(), left.end(), right.begin(), right.end());
}
//String + string concat
template<String Left, String Right>
constexpr auto operator+(Left&& l, Right&& r)
//uses deduction guide whereas std::is_nothrow_constructible couldn't
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(l), std::forward<Right>(r))))
{
return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
}
template<String Right>
constexpr auto operator+(typename std::decay_t<Right>::const_pointer left, Right&& right)
noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::basic_string_view(left), std::forward<Right>(right))))
{
return string_cat_expr(rexy::basic_string_view(left), std::forward<Right>(right));
}
template<String Left>
constexpr auto operator+(Left&& left, typename std::decay_t<Left>::const_pointer right)
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(left), rexy::basic_string_view(right))))
{
return rexy::string_cat_expr(std::forward<Left>(left), rexy::basic_string_view(right));
}
//String concat assign
template<BasicString Left, String Right>
constexpr decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left, decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r));
}
template<BasicString Left>
constexpr decltype(auto) operator+=(Left& l, typename std::decay_t<Left>::const_pointer r)
noexcept(noexcept(l + r) && std::is_nothrow_assignable<Left, decltype(l + r)>::value)
{
return l = (l + r);
}
template<BasicString T, class Char>
constexpr std::size_t find_first_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
for(auto it = t.cbegin() + start;it != t.cend();++it){
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
return it - t.cbegin();
}
}
}
return rexy::npos;
}
template<BasicString T, class Char>
constexpr std::size_t find_first_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
for(auto it = t.cbegin() + start;it != t.cend();++it){
bool found = false;
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
found = true;
break;
}
}
if(!found){
return it - t.cbegin();
}
}
return rexy::npos;
}
template<BasicString T, class Char>
constexpr std::size_t find_last_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
const auto b = t.cend() - 1;
const auto e = t.cbegin() - 1 - start;
for(auto it = b;it != e;--it){
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
return it - t.cbegin();
}
}
}
return rexy::npos;
}
template<BasicString T, class Char>
constexpr std::size_t find_last_not_of(T&& t, const Char* c, std::size_t start, std::size_t size)noexcept{
if(start > t.length()){
return rexy::npos;
}
const auto b = t.cend() - 1;
const auto e = t.cbegin() - 1 - start;
for(auto it = b;it != e;--it){
bool found = false;
for(std::size_t i = 0;i < size;++i){
if(*it == c[i]){
found = true;
break;
}
}
if(!found){
return it - t.cbegin();
}
}
return rexy::npos;
}
}
#endif

View File

@ -1,37 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_20_TO_ADDRESS_HPP
#define REXY_COMPAT_20_TO_ADDRESS_HPP
#include <memory> //to_address
namespace rexy::compat::cpp20{
template<class T>
constexpr T* to_address(T* p)noexcept{
return std::to_address(p);
}
template<class Ptr>
constexpr auto to_address(const Ptr& p)noexcept{
return std::to_address(p);
}
}
#endif

View File

@ -1,30 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_if_consteval
#if defined(__cpp_if_consteval)
#define REXY_if_consteval if consteval
#define REXY_if_not_consteval if not consteval
#elif defined(__cpp_lib_is_constant_evaluated)
#include <type_traits> //is_constant_evaluated
#define REXY_if_consteval if(std::is_constant_evaluated())
#define REXY_if_not_consteval if(!std::is_constant_evaluated())
#endif //__cpp_if_consteval
#endif

View File

@ -1,48 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_UTIL_SOURCE_LOCATION_HPP
#define REXY_UTIL_SOURCE_LOCATION_HPP
#include <version> //feature test macro
#ifndef __cpp_lib_source_location
#include "cpp17/source_location.hpp"
namespace rexy::compat{
using source_location = cpp17::source_location;
}
#else //__cpp_lib_source_location
#include "cpp20/source_location.hpp"
namespace rexy::compat{
using source_location = cpp20::source_location;
}
#endif //__cpp_lib_source_location
#endif

View File

@ -1,45 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_CPP20_HPP
#define REXY_COMPAT_CPP20_HPP
#define REXY_REQUIRES_CPP20 static_assert(__cplusplus >= 202002L, "C++20 is required to use this file.")
#if __cplusplus >= 202002L
#define REXY_CPP20_CONSTEXPR constexpr
#define REXY_CPP20_CONSTEVAL consteval
#else //__cpp_consteval
#define REXY_CPP20_CONSTEXPR
#define REXY_CPP20_CONSTEVAL constexpr
#endif //__cpp_consteval
#if __cplusplus >= 202300L
#define REXY_STANDARD_CPP23
#endif
#if __cplusplus >= 202002L
#define REXY_STANDARD_CPP20
#endif
#if __cplusplus >= 201703L
#define REXY_STANDARD_CPP17
#endif
#if __cplusplus < 201703L
#error "Requires minimum C++17 standard"
#endif //__cplusplus
#endif

View File

@ -1,43 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_TO_ADDRESS_HPP
#define REXY_COMPAT_TO_ADDRESS_HPP
#ifdef __cpp_lib_to_address
#include "cpp20/to_address.hpp"
namespace rexy::compat{
using cpp20::to_address;
}
#else //__cpp_lib_to_address
#include "cpp17/to_address.hpp"
namespace rexy::compat{
using cpp17::to_address;
}
#endif //__cpp_lib_to_address
#endif

View File

@ -1,29 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_COMPAT_TRAITS_HPP
#define REXY_COMPAT_TRAITS_HPP
#ifdef REXY_STANDARD_CPP20
#include "cpp20/traits.hpp"
#else // REXY_STANDARD_CPP26
#include "cpp17/traits.hpp"
#endif // REXY_STANDARD_CPP26
#endif

View File

@ -27,12 +27,12 @@
namespace rexy::cx{ namespace rexy::cx{
template<class T, std::size_t N> template<class T, size_t N>
class array class array
{ {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
using reference = T&; using reference = T&;
using const_reference = const T&; using const_reference = const T&;
@ -125,7 +125,7 @@ namespace rexy::cx{
} }
}; };
template<std::size_t N> template<size_t N>
class array<bool,N> : public detail::bool_specialize_base class array<bool,N> : public detail::bool_specialize_base
{ {
public: public:

View File

@ -0,0 +1,32 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_CX_CX_STRING_HASH_HPP
#define REXY_CX_CX_STRING_HASH_HPP
#include "../string_hash.hpp"
#include "string.hpp"
namespace rexy::cx{
template<size_t N>
struct hash<rexy::cx::string<N>> : public string_hash<rexy::cx::string<N>>{};
}
#endif

View File

@ -23,13 +23,13 @@
#include <utility> //move, forward, pair #include <utility> //move, forward, pair
#include <climits> //CHAR_BIT #include <climits> //CHAR_BIT
#include "../../utility.hpp" //swap #include "../../utility.hpp" //swap
#include "../../compat/standard.hpp"
namespace rexy::cx::detail{ namespace rexy::cx::detail{
class bool_specialize_base class bool_specialize_base
{ {
protected: protected:
using size_type = std::size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
static constexpr size_type bits_per_byte = CHAR_BIT; static constexpr size_type bits_per_byte = CHAR_BIT;
@ -59,7 +59,7 @@ namespace rexy::cx::detail{
m_offset(offset){} m_offset(offset){}
constexpr boolean(const boolean&)noexcept = default; constexpr boolean(const boolean&)noexcept = default;
constexpr boolean(boolean&&)noexcept = default; constexpr boolean(boolean&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~boolean(void)noexcept = default; ~boolean(void)noexcept = default;
constexpr boolean& operator=(const boolean& b)noexcept{ constexpr boolean& operator=(const boolean& b)noexcept{
return *this = static_cast<bool>(b); return *this = static_cast<bool>(b);
@ -86,15 +86,15 @@ namespace rexy::cx::detail{
constexpr booleans(void)noexcept = default; constexpr booleans(void)noexcept = default;
constexpr booleans(const booleans&)noexcept = default; constexpr booleans(const booleans&)noexcept = default;
constexpr booleans(booleans&&)noexcept = default; constexpr booleans(booleans&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~booleans(void)noexcept = default; ~booleans(void)noexcept = default;
constexpr booleans& operator=(const booleans&)noexcept = default; constexpr booleans& operator=(const booleans&)noexcept = default;
constexpr booleans& operator=(booleans&&)noexcept = default; constexpr booleans& operator=(booleans&&)noexcept = default;
constexpr boolean operator[](std::size_t i){ constexpr boolean operator[](size_t i){
return boolean{m_value, i}; return boolean{m_value, i};
} }
constexpr boolean operator[](std::size_t i)const{ constexpr boolean operator[](size_t i)const{
return boolean{const_cast<uchar&>(m_value), i}; return boolean{const_cast<uchar&>(m_value), i};
} }
constexpr uchar& data(void){ constexpr uchar& data(void){
@ -121,7 +121,7 @@ namespace rexy::cx::detail{
m_offset(offset){} m_offset(offset){}
constexpr bool_iter(const bool_iter&)noexcept = default; constexpr bool_iter(const bool_iter&)noexcept = default;
constexpr bool_iter(bool_iter&&)noexcept = default; constexpr bool_iter(bool_iter&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~bool_iter(void)noexcept = default; ~bool_iter(void)noexcept = default;
constexpr bool_iter& operator=(const bool_iter&)noexcept = default; constexpr bool_iter& operator=(const bool_iter&)noexcept = default;
constexpr bool_iter& operator=(bool_iter&&)noexcept = default; constexpr bool_iter& operator=(bool_iter&&)noexcept = default;
@ -209,7 +209,7 @@ namespace rexy::cx::detail{
m_offset(b.m_offset){} m_offset(b.m_offset){}
constexpr const_bool_iter(const const_bool_iter&)noexcept = default; constexpr const_bool_iter(const const_bool_iter&)noexcept = default;
constexpr const_bool_iter(const_bool_iter&&)noexcept = default; constexpr const_bool_iter(const_bool_iter&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~const_bool_iter(void)noexcept = default; ~const_bool_iter(void)noexcept = default;
constexpr const_bool_iter& operator=(const const_bool_iter&)noexcept = default; constexpr const_bool_iter& operator=(const const_bool_iter&)noexcept = default;
constexpr const_bool_iter& operator=(const_bool_iter&&)noexcept = default; constexpr const_bool_iter& operator=(const_bool_iter&&)noexcept = default;

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -25,7 +25,8 @@
#include "../hash.hpp" #include "../hash.hpp"
#include <climits> //CHAR_BIT #include <climits> //CHAR_BIT
#include <cstddef> //std::size_t, ptrdiff_t #include <cstddef> //size_t, ptrdiff_t
#include <utility> //pair
#include <type_traits> //decay #include <type_traits> //decay
#include <initializer_list> #include <initializer_list>
@ -42,14 +43,14 @@ namespace rexy::cx{
template<class Key, class Value> template<class Key, class Value>
element(Key,Value) -> element<Key,Value>; element(Key,Value) -> element<Key,Value>;
template<class Key, class Value, std::size_t N, class Hash = hash<Key>> template<class Key, class Value, size_t N, class Hash = hash<Key>>
class hashmap class hashmap
{ {
public: public:
using key_type = Key; using key_type = Key;
using mapped_type = Value; using mapped_type = Value;
using value_type = element<Key,Value>; using value_type = element<Key,Value>;
using size_type = std::size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
using hasher = Hash; using hasher = Hash;
using reference = mapped_type&; using reference = mapped_type&;
@ -64,15 +65,16 @@ namespace rexy::cx{
private: private:
array<value_type,N> m_elements; //perfect hash table array<mapped_type,N> m_values; //perfect hash table
array<size_type,N> m_g; //'salt' values for indexing into the perfect hash table array<size_type,N> m_g; //'salt' values for indexing into the perfect hash table
array<size_type,N> m_key_hashes; //full hash values for keys to verify good index values
public: public:
constexpr hashmap(const value_type(&elements)[N]) constexpr hashmap(const value_type(&elements)[N])
noexcept(std::is_nothrow_default_constructible<value_type>::value && noexcept(std::is_nothrow_default_constructible<value_type>::value &&
std::is_nothrow_copy_constructible<value_type>::value && std::is_nothrow_copy_constructible<value_type>::value &&
std::is_nothrow_move_assignable<mapped_type>::value && std::is_nothrow_move_assignable<mapped_type>::value &&
std::is_nothrow_invocable<Hash,Key,std::size_t>::value); std::is_nothrow_invocable<Hash,Key,size_t>::value);
//no key checks. give a correct key or get a random answer :) //no key checks. give a correct key or get a random answer :)
template<class U, class UHash = hash<std::decay_t<U>>> template<class U, class UHash = hash<std::decay_t<U>>>
@ -81,12 +83,123 @@ namespace rexy::cx{
constexpr const_reference operator[](U&& u)const noexcept; constexpr const_reference operator[](U&& u)const noexcept;
template<class U, class UHash = hash<std::decay_t<U>>> template<class U, class UHash = hash<std::decay_t<U>>>
constexpr bool contains(U&& u)const noexcept; constexpr bool is_valid(U&& u)const noexcept;
}; };
template<class Key, class Value, size_t N, class Hash>
constexpr hashmap<Key,Value,N,Hash>::hashmap(const value_type(&elements)[N])
noexcept(std::is_nothrow_default_constructible<value_type>::value &&
std::is_nothrow_copy_constructible<value_type>::value &&
std::is_nothrow_move_assignable<mapped_type>::value &&
std::is_nothrow_invocable<Hash,Key,size_t>::value)
{
array<vector<value_type,N>,N> buckets;
size_type current_bucket = 0;
//place all keys into buckets
for(auto& element : elements){
buckets[Hash{}(element.key, 0) % max_size].push_back(element);
}
//sort the buckets based on size, largest first
quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{
return left.size() > right.size();
});
//for each bucket, try different values of 'd' to try to find a hash that doesn't collide
for(current_bucket = 0;current_bucket < buckets.size();++current_bucket){
auto& bucket = buckets[current_bucket];
//only handle buckets containing collisions
if(bucket.size() <= 1)
break;
const auto hashval = Hash{}(bucket[0].key, 0);
array<bool,N> pass_slots_used;
vector<size_type,N> pass_slots;
size_type d = 1;
for(size_type i = 0;i < bucket.size();){
size_type slot = Hash{}(bucket[i].key, d) % max_size;
if(pass_slots_used[slot] || m_key_hashes[slot] != 0){
//slot already in use, try another value for 'd'
++d;
i = 0;
pass_slots_used.fill(false);
pass_slots.clear();
}else{
//slot is good to go
pass_slots_used[slot] = true;
pass_slots.push_back(slot);
++i;
}
}
//store the successful value of 'd' at index of the first hash for this bucket
m_g[hashval % max_size] = d;
//take the value from the temporary bucket into the permanent slot
for(size_type i = 0;i < bucket.size();++i){
m_values[pass_slots[i]] = std::move(bucket[i].value);
m_key_hashes[pass_slots[i]] = hashval;
}
}
//Handle remaining single value buckets
size_type next_free_slot = 0;
for(;current_bucket < buckets.size();++current_bucket){
auto& bucket = buckets[current_bucket];
if(bucket.size() == 0)
break;
const auto hashval = Hash{}(bucket[0].key, 0);
for(;m_key_hashes[next_free_slot] != 0;++next_free_slot);
m_g[Hash{}(bucket[0].key, 0) % max_size] = (next_free_slot | single_bucket_bit);
m_values[next_free_slot] = std::move(bucket[0].value);
m_key_hashes[next_free_slot] = hashval;
}
}
//no key checks. give a correct key or get a random answer :)
template<class Key, class Value, size_t N, class Hash>
template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)noexcept -> reference{
auto d = m_g[UHash{}(std::forward<U>(key), 0) % max_size];
if(d & single_bucket_bit)
return m_values[d & ~single_bucket_bit];
return m_values[UHash{}(std::forward<U>(key), d) % max_size];
}
template<class Key, class Value, size_t N, class Hash>
template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)const noexcept -> const_reference{
auto d = m_g[UHash{}(std::forward<U>(key), 0) % max_size];
if(d & single_bucket_bit)
return m_values[d & ~single_bucket_bit];
return m_values[UHash{}(std::forward<U>(key), d) % max_size];
}
template<class Key, class Value, size_t N, class Hash>
template<class U, class UHash>
constexpr bool hashmap<Key,Value,N,Hash>::is_valid(U&& key)const noexcept{
const auto hashval = UHash{}(std::forward<U>(key), 0);
const auto d = m_g[hashval % max_size];
if(d & single_bucket_bit){
return m_key_hashes[d & ~single_bucket_bit] == hashval;
}
return m_key_hashes[UHash{}(std::forward<U>(key), d) % max_size] == hashval;
}
template<class Key, class Value, size_t N, class Hash = hash<Key>>
constexpr auto make_hashmap(const typename hashmap<Key,Value,N,Hash>::value_type(&list)[N]){
return hashmap<Key,Value,N,Hash>(list);
}
} }
#include "hashmap.tpp" #ifdef REXY_STRING_BASE_HPP
#include "../string_hash.hpp"
#endif
#endif #endif

View File

@ -1,139 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_CX_HASHMAP_TPP
#define REXY_CX_HASHMAP_TPP
#include <utility> //move, forward
namespace rexy::cx{
template<class Key, class Value, std::size_t N, class Hash>
constexpr hashmap<Key,Value,N,Hash>::hashmap(const value_type(&elements)[N])
noexcept(std::is_nothrow_default_constructible<value_type>::value &&
std::is_nothrow_copy_constructible<value_type>::value &&
std::is_nothrow_move_assignable<mapped_type>::value &&
std::is_nothrow_invocable<Hash,Key,std::size_t>::value)
{
array<vector<value_type,N>,N> buckets;
array<size_type,N> key_hashes; //full hash values for keys to verify good index values
size_type current_bucket = 0;
//place all keys into buckets
for(auto& element : elements){
buckets[Hash{}(element.key, 0) % max_size].push_back(element);
}
//sort the buckets based on size, largest first
quicksort(buckets.begin(), buckets.end(), [](auto&& left, auto&& right) -> bool{
return left.size() > right.size();
});
//for each bucket, try different values of 'd' to try to find a hash that doesn't collide
for(current_bucket = 0;current_bucket < buckets.size();++current_bucket){
auto& bucket = buckets[current_bucket];
//only handle buckets containing collisions
if(bucket.size() <= 1)
break;
const auto hashval = Hash{}(bucket[0].key, 0);
array<bool,N> pass_slots_used;
vector<size_type,N> pass_slots;
size_type d = 1;
for(size_type i = 0;i < bucket.size();){
size_type slot = Hash{}(bucket[i].key, d) % max_size;
if(pass_slots_used[slot] || key_hashes[slot] != 0){
//slot already in use, try another value for 'd'
++d;
i = 0;
pass_slots_used.fill(false);
pass_slots.clear();
}else{
//slot is good to go
pass_slots_used[slot] = true;
pass_slots.push_back(slot);
++i;
}
}
//store the successful value of 'd' at index of the first hash for this bucket
m_g[hashval % max_size] = d;
//take the value from the temporary bucket into the permanent slot
for(size_type i = 0;i < bucket.size();++i){
m_elements[pass_slots[i]] = std::move(bucket[i]);
key_hashes[pass_slots[i]] = hashval;
}
}
//Handle remaining single value buckets
size_type next_free_slot = 0;
for(;current_bucket < buckets.size();++current_bucket){
auto& bucket = buckets[current_bucket];
if(bucket.size() == 0)
break;
const auto hashval = Hash{}(bucket[0].key, 0);
for(;key_hashes[next_free_slot] != 0;++next_free_slot);
m_g[Hash{}(bucket[0].key, 0) % max_size] = (next_free_slot | single_bucket_bit);
m_elements[next_free_slot] = std::move(bucket[0]);
key_hashes[next_free_slot] = hashval;
}
}
//no key checks. give a correct key or get a random answer :)
template<class Key, class Value, std::size_t N, class Hash>
template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)noexcept -> reference{
auto d = m_g[UHash{}(std::forward<U>(key), 0) % max_size];
if(d & single_bucket_bit)
return m_elements[d & ~single_bucket_bit].value;
return m_elements[UHash{}(std::forward<U>(key), d) % max_size].value;
}
template<class Key, class Value, std::size_t N, class Hash>
template<class U, class UHash>
constexpr auto hashmap<Key,Value,N,Hash>::operator[](U&& key)const noexcept -> const_reference{
auto d = m_g[UHash{}(std::forward<U>(key), 0) % max_size];
if(d & single_bucket_bit)
return m_elements[d & ~single_bucket_bit].value;
return m_elements[UHash{}(std::forward<U>(key), d) % max_size].value;
}
template<class Key, class Value, std::size_t N, class Hash>
template<class U, class UHash>
constexpr bool hashmap<Key,Value,N,Hash>::contains(U&& key)const noexcept{
const auto hashval = UHash{}(std::forward<U>(key), 0);
const auto d = m_g[hashval % max_size];
if(d & single_bucket_bit){
return m_elements[d & ~single_bucket_bit].key == std::forward<U>(key);
}
return m_elements[UHash{}(std::forward<U>(key), d) % max_size].key == std::forward<U>(key);
}
template<class Key, class Value, std::size_t N, class Hash = hash<Key>>
constexpr auto make_hashmap(const typename hashmap<Key,Value,N,Hash>::value_type(&list)[N]){
return hashmap<Key,Value,N,Hash>(list);
}
}
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,69 +19,55 @@
#ifndef REXY_CX_STRING_HPP #ifndef REXY_CX_STRING_HPP
#define REXY_CX_STRING_HPP #define REXY_CX_STRING_HPP
#include <cstddef> //ptrdiff_t, size_t
namespace rexy::cx{ namespace rexy::cx{
template<std::size_t N, class Char> template<size_t N, class Char>
class string; class string;
} }
#include "../string_base.hpp" //string_cat_expr #include "../string_base.hpp"
#include "../string_view.hpp" #include "../utility.hpp"
#include "../utility.hpp" //strlen, strcmp #include <type_traits>
#include "../detail/string_appender.hpp" #include <cstddef> //ptrdiff_t
#include "../traits.hpp" //remove_cvref
#include <type_traits> //nothrow_invocable, integral_constant, declval
#include <iterator> //reverse_iterator
#include "../compat/standard.hpp" //This is different from rexy::static_string in that this doesn't hold a pointer to a constant string array.
//This holds a mutable array of data which can be modified during compile time. static_string is
//This is different from rexy::string_view in that this doesn't hold a pointer to a constant string array.
//This holds a mutable array of data which can be modified during compile time. string_view is
//designed to be a thin wrapper around a raw char*, this is designed to allow compile time string concatenation //designed to be a thin wrapper around a raw char*, this is designed to allow compile time string concatenation
namespace rexy::cx{ namespace rexy::cx{
template<std::size_t N, class Char = char> template<size_t N, class Char = char>
class string class string
{ {
public: public:
using value_type = Char; using value_type = Char;
using size_type = std::size_t; using size_type = size_t;
using difference_type = std::ptrdiff_t; using difference_type = ptrdiff_t;
using pointer = value_type*; using pointer = value_type*;
using const_pointer = const value_type*; using const_pointer = const value_type*;
using reference = value_type&; using reference = value_type&;
using const_reference = const value_type&; using const_reference = const value_type&;
using iterator = pointer; using iterator = pointer;
using const_iterator = const_pointer; using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public:
static constexpr size_type max_size = N;
static constexpr size_type npos = size_type(-1);
public: public:
static constexpr size_t max_size = N;
private:
value_type m_data[N] = {}; value_type m_data[N] = {};
size_type m_length = 0; size_type m_length = 0;
public: public:
constexpr string(void) = default; constexpr string(void) = default;
template<size_type M> template<size_type M>
constexpr string(const value_type(&data)[M])noexcept: constexpr string(const char(&data)[M])noexcept:
m_length(M) m_length(M)
{ {
static_assert(M <= N); static_assert(M <= N);
for(size_type i = 0;i < M;++i){ for(size_type i = 0;i < M;++i){
m_data[i] = data[i]; m_data[i] = data[i];
} }
if(m_data[m_length - 1] == 0){
--m_length; //exclude null terminator in length
}
} }
constexpr string(const_pointer data)noexcept: constexpr string(const_pointer data)noexcept:
m_length(rexy::strlen(data)) m_length(strlen(data))
{ {
for(size_type i = 0;i < m_length;++i){ for(size_type i = 0;i < m_length;++i){
m_data[i] = data[i]; m_data[i] = data[i];
@ -95,7 +81,7 @@ namespace rexy::cx{
} }
} }
constexpr string(const rexy::basic_string_view<value_type>& str)noexcept: constexpr string(const rexy::static_string<value_type>& str)noexcept:
m_length(str.length()) m_length(str.length())
{ {
for(size_type i = 0;i < m_length;++i){ for(size_type i = 0;i < m_length;++i){
@ -104,7 +90,7 @@ namespace rexy::cx{
} }
template<class Left, class Right> template<class Left, class Right>
constexpr string(const rexy::string_cat_expr<Left,Right>& expr) constexpr string(const rexy::string_cat_expr<Left,Right>& expr)
noexcept(std::is_nothrow_invocable<rexy::detail::string_appender<cx::string<N,Char>>, decltype(expr)>::value) noexcept(std::is_nothrow_invocable<rexy::detail::string_appender<cx::string<N>>, decltype(expr)>::value)
{ {
rexy::detail::string_appender<cx::string<N,value_type>> append(*this); rexy::detail::string_appender<cx::string<N,value_type>> append(*this);
append(expr); append(expr);
@ -112,10 +98,10 @@ namespace rexy::cx{
constexpr string(const string&)noexcept = default; constexpr string(const string&)noexcept = default;
constexpr string(string&&)noexcept = default; constexpr string(string&&)noexcept = default;
REXY_CPP20_CONSTEXPR ~string(void)noexcept = default; ~string(void)noexcept = default;
constexpr string& operator=(const_pointer c)noexcept{ constexpr string& operator=(const_pointer c)noexcept{
m_length = rexy::strlen(c); m_length = strlen(c);
for(size_type i = 0;i < m_length;++i){ for(size_type i = 0;i < m_length;++i){
m_data[i] = c[i]; m_data[i] = c[i];
} }
@ -124,64 +110,45 @@ namespace rexy::cx{
constexpr string& operator=(const string&)noexcept = default; constexpr string& operator=(const string&)noexcept = default;
constexpr string& operator=(string&&)noexcept = default; constexpr string& operator=(string&&)noexcept = default;
constexpr bool operator==(const string& s)noexcept{return !rexy::strcmp(m_data, s.m_data);}
constexpr bool operator!=(const string& s)noexcept{return rexy::strcmp(m_data, s.m_data);}
constexpr size_type length(void)const noexcept{return m_length;} constexpr size_type length(void)const noexcept{
constexpr size_type size(void)const noexcept{return m_length;} return m_length;
constexpr size_type capacity(void)const noexcept{return max_size;}
constexpr bool empty(void)const noexcept{return m_length == 0;}
constexpr pointer c_str(void)noexcept{return m_data;}
constexpr const_pointer c_str(void)const noexcept{return m_data;}
constexpr pointer get(void)noexcept{return m_data;}
constexpr const_pointer get(void)const noexcept{return m_data;}
constexpr operator pointer(void)noexcept{return m_data;}
constexpr operator const_pointer(void)const noexcept{return m_data;}
constexpr reference operator[](size_type i)noexcept{return m_data[i];}
constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];}
constexpr reference at(size_type i)noexcept{return m_data[i];}
constexpr const_reference at(size_type i)const noexcept{return m_data[i];}
constexpr const_reference front(size_type i)const noexcept{return m_data[0];}
constexpr const_reference back(size_type i)const noexcept{return m_data[m_length-1];}
constexpr const_iterator search(const basic_string_view<value_type>& s)const{
return two_way_search(cbegin(), cend(), s.cbegin(), s.cend());
} }
constexpr const_iterator search(const_pointer c)const{ constexpr size_type capacity(void)const noexcept{
return search(basic_string_view<value_type>{c}); return max_size;
} }
template<class Searcher> constexpr pointer c_str(void)noexcept{
constexpr const_iterator search(const basic_string_view<value_type>& s, Searcher&& searcher)const{ return m_data;
return searcher(cbegin(), cend(), s.cbegin(), s.cend());
} }
template<class Searcher> constexpr const_pointer c_str(void)const noexcept{
constexpr const_iterator search(const_pointer c, Searcher&& searcher)const{ return m_data;
return search(basic_string_view<value_type>{c}, searcher); }
constexpr pointer get(void)noexcept{
return m_data;
}
constexpr const_pointer get(void)const noexcept{
return m_data;
}
constexpr operator pointer(void)noexcept{
return m_data;
}
constexpr operator const_pointer(void)const noexcept{
return m_data;
} }
constexpr iterator begin(void)noexcept{return m_data;} constexpr bool valid(void)const noexcept{
constexpr const_iterator begin(void)const noexcept{return m_data;} return m_length > 0;
constexpr const_iterator cbegin(void)const noexcept{return m_data;} }
constexpr iterator end(void)noexcept{return m_data+m_length;} constexpr reference operator[](size_type i)noexcept{
constexpr const_iterator end(void)const noexcept{return m_data+m_length;} return m_data[i];
constexpr const_iterator cend(void)const noexcept{return m_data+m_length;} }
constexpr const_reference operator[](size_type i)const noexcept{
constexpr const_reverse_iterator rbegin(void)const{return const_reverse_iterator(m_data+m_length);} return m_data[i];
constexpr const_reverse_iterator rend(void)const{return const_reverse_iterator(m_data-1);} }
constexpr const_reverse_iterator crbegin(void)const{return rbegin();}
constexpr const_reverse_iterator crend(void)const{return rend();}
constexpr bool valid(void)const noexcept{return m_length > 0;}
constexpr bool compare(const string& s)const{return *this == s;}
constexpr bool compare(const_pointer c)const{return *this == c;}
constexpr bool resize(size_type i)noexcept{ constexpr bool resize(size_type i)noexcept{
if(i >= capacity()){ if(i >= capacity())
return false; return false;
}
m_length = i; m_length = i;
m_data[m_length] = 0; m_data[m_length] = 0;
return true; return true;
@ -192,48 +159,48 @@ namespace rexy::cx{
m_data[m_length++] = data[i]; m_data[m_length++] = data[i];
} }
} }
constexpr void append(const_pointer data)noexcept{append(data, rexy::strlen(data));} constexpr void append(const_pointer data)noexcept{
constexpr void append(const string& s)noexcept{append(s.get(), s.length());} append(data, strlen(data));
constexpr void append(const rexy::basic_string_view<value_type>& s)noexcept{append(s.get(), s.length());}
constexpr size_type find_first_of(value_type v, size_type start = 0)const{
return rexy::find_first_of(*this, &v, start, 1);
} }
constexpr size_type find_first_of(const_pointer c, size_type pos = 0)const{ constexpr void append(const string& s)noexcept{
return rexy::find_first_of(*this, c, pos, rexy::strlen(c)); append(s.get(), s.length());
} }
constexpr size_type find_first_of(const_pointer c, size_type start, size_type size)const{ constexpr void append(const rexy::static_string<value_type>& s)noexcept{
return rexy::find_first_of(*this, c, start, size); append(s.get(), s.length());
} }
constexpr size_type find_last_of(value_type v, size_type start = 0)const{
return rexy::find_last_of(*this, &v, start, 1);
}
constexpr size_type find_last_of(const_pointer c, size_type start = 0)const{
return rexy::find_last_of(*this, c, start, rexy::strlen(c));
}
constexpr size_type find_last_of(const_pointer c, size_type start, size_type size)const{
return rexy::find_last_of(*this, c, start, size);
}
};
template<class Char, std::size_t N>
string(const Char(&data)[N]) -> string<N, Char>;
template<class... Ts>
struct is_cx_string{
template<class Char, std::size_t N>
static std::true_type check(cx::string<N,Char>);
static std::false_type check(...);
static constexpr bool value = (decltype(check(std::declval<rexy::remove_cvref_t<Ts>>()))::value && ...);
}; };
namespace detail{
template<class T>
struct is_cx_string_helper{
static constexpr bool value = false;
};
template<size_t N, class Char>
struct is_cx_string_helper<cx::string<N,Char>>{
static constexpr bool value = true;
};
template<class... Ts>
struct is_cx_string{
static constexpr bool value = (is_cx_string_helper<std::decay_t<Ts>>::value && ...);
};
}
template<class Str1, class Str2, std::enable_if_t<detail::is_cx_string<Str1,Str2>::value,int> = 0>
constexpr auto operator+(Str1&& l, Str2&& r)noexcept{
return string_cat_expr(std::forward<Str1>(l), std::forward<Str2>(r));
}
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(Str1&& l, const char* r)noexcept{
return string_cat_expr(std::forward<Str1>(l), rexy::static_string<char>(r));
}
template<class Str1, std::enable_if_t<detail::is_cx_string<Str1>::value,int> = 0>
constexpr auto operator+(const char* l, Str1&& r)noexcept{
return string_cat_expr(rexy::static_string<char>(l), std::forward<Str1>(r));
}
} }
#ifdef __cpp_concepts #ifdef REXY_CX_HASH_HPP
#include "../compat/cpp20/cx/string.hpp" #include "cx_string_hash.hpp"
#else //__cpp_concepts #endif
#include "../compat/cpp17/cx/string.hpp"
#endif //__cpp_concepts
#endif #endif

View File

@ -24,18 +24,17 @@
#include "detail/bool_specialize_base.hpp" #include "detail/bool_specialize_base.hpp"
#include "../utility.hpp" //swap #include "../utility.hpp" //swap
#include "../compat/standard.hpp"
#include <type_traits> #include <type_traits>
namespace rexy::cx{ namespace rexy::cx{
template<class T, std::size_t N> template<class T, size_t N>
class vector class vector
{ {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
using iterator = T*; using iterator = T*;
using const_iterator = const T*; using const_iterator = const T*;
@ -64,7 +63,7 @@ namespace rexy::cx{
m_size = min(count, max_elements); m_size = min(count, max_elements);
} }
REXY_CPP20_CONSTEXPR ~vector(void)noexcept = default; ~vector(void)noexcept = default;
constexpr vector& operator=(const vector&)noexcept(std::is_nothrow_copy_assignable<T>::value) = default; constexpr vector& operator=(const vector&)noexcept(std::is_nothrow_copy_assignable<T>::value) = default;
constexpr vector& operator=(vector&&)noexcept(std::is_nothrow_move_assignable<T>::value) = default; constexpr vector& operator=(vector&&)noexcept(std::is_nothrow_move_assignable<T>::value) = default;
@ -244,7 +243,7 @@ namespace rexy::cx{
} }
}; };
template<std::size_t N> template<size_t N>
class vector<bool,N> : public detail::bool_specialize_base class vector<bool,N> : public detail::bool_specialize_base
{ {
public: public:
@ -284,7 +283,7 @@ namespace rexy::cx{
m_size = min(count, max_elements); m_size = min(count, max_elements);
} }
REXY_CPP20_CONSTEXPR ~vector(void)noexcept = default; ~vector(void)noexcept = default;
constexpr vector& operator=(const vector&)noexcept = default; constexpr vector& operator=(const vector&)noexcept = default;
constexpr vector& operator=(vector&&)noexcept = default; constexpr vector& operator=(vector&&)noexcept = default;

View File

@ -1,212 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DEBUG_PRINT_HPP
#define REXY_DEBUG_PRINT_HPP
#include "detail/debug_config.hpp"
//Debug output section
#if LIBREXY_ENABLE_DEBUG_LEVEL > 0
#define LIBREXY_ENABLE_DEBUG_OUTPUT
#endif
#if LIBREXY_ENABLE_DEBUG_LEVEL > 2
#define LIBREXY_ENABLE_DEBUG_VERBOSE_OUTPUT
#endif
#ifdef LIBREXY_ENABLE_DEBUG_OUTPUT
#include <cstdio> //fprintf, vfprintf
#include <utility> //forward
#include "compat/source_location.hpp"
namespace rexy::debug{
namespace detail{
static constexpr const char color_red[] = "\033[38;5;9m";
static constexpr const char color_yellow[] = "\033[38;5;11m";
static constexpr const char color_green[] = "\033[38;5;2m";
static constexpr const char color_blue[] = "\033[38;5;12m";
static constexpr const char color_clear[] = "\033[0m";
}
template<class... Args>
struct print{
explicit print(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){
std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line());
std::fprintf(stderr, std::forward<Args>(args)...);
}
print(const print&) = delete;
print(print&&) = delete;
print& operator=(const print&) = delete;
print& operator=(print&&) = delete;
};
template<class... Args>
print(Args&&...) -> print<Args&&...>;
#ifdef LIBREXY_ENABLE_COLOR_DEBUG
template<class... Args>
struct print_succ{
explicit print_succ(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){
std::fprintf(stderr, "%s", detail::color_green);
std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line());
std::fprintf(stderr, std::forward<Args>(args)...);
std::fprintf(stderr, "%s", detail::color_clear);
}
print_succ(const print_succ&) = delete;
print_succ(print_succ&&) = delete;
print_succ& operator=(const print_succ&) = delete;
print_succ& operator=(print_succ&&) = delete;
};
template<class... Args>
struct print_info{
explicit print_info(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){
std::fprintf(stderr, "%s", detail::color_blue);
std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line());
std::fprintf(stderr, std::forward<Args>(args)...);
std::fprintf(stderr, "%s", detail::color_clear);
}
print_info(const print_info&) = delete;
print_info(print_info&&) = delete;
print_info& operator=(const print_info&) = delete;
print_info& operator=(print_info&&) = delete;
};
template<class... Args>
struct print_warn{
explicit print_warn(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){
std::fprintf(stderr, "%s", detail::color_yellow);
std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line());
std::fprintf(stderr, std::forward<Args>(args)...);
std::fprintf(stderr, "%s", detail::color_clear);
}
print_warn(const print_warn&) = delete;
print_warn(print_warn&&) = delete;
print_warn& operator=(const print_warn&) = delete;
print_warn& operator=(print_warn&&) = delete;
};
template<class... Args>
struct print_error{
explicit print_error(Args&&... args, const rexy::compat::source_location& loc = rexy::compat::source_location::current()){
std::fprintf(stderr, "%s", detail::color_red);
std::fprintf(stderr, "%s:%s:%d: ", loc.file_name(), loc.function_name(), loc.line());
std::fprintf(stderr, std::forward<Args>(args)...);
std::fprintf(stderr, "%s", detail::color_clear);
}
print_error(const print_error&) = delete;
print_error(print_error&&) = delete;
print_error& operator=(const print_error&) = delete;
print_error& operator=(print_error&&) = delete;
};
#else
template<class... Args>
class print_succ : public print<Args...>{
public:
using print<Args...>::print;
};
template<class... Args>
class print_info : public print<Args...>{
public:
using print<Args...>::print;
};
template<class... Args>
class print_warn : public print<Args...>{
public:
using print<Args...>::print;
};
template<class... Args>
class print_error : public print<Args...>{
public:
using print<Args...>::print;
};
#endif //LIBREXY_ENABLE_COLOR_DEBUG
template<class... Args>
print_warn(Args&&...) -> print_warn<Args&&...>;
template<class... Args>
print_error(Args&&...) -> print_error<Args&&...>;
template<class... Args>
print_info(Args&&...) -> print_info<Args&&...>;
template<class... Args>
print_succ(Args&&...) -> print_succ<Args&&...>;
#ifdef LIBREXY_ENABLE_DEBUG_VERBOSE_OUTPUT
namespace verbose{
template<class... Args>
class print : public ::rexy::debug::print<Args...>{
public:
using ::rexy::debug::print<Args...>::print;
};
template<class... Args>
class print_succ : public ::rexy::debug::print_succ<Args...>{
public:
using ::rexy::debug::print_succ<Args...>::print_succ;
};
template<class... Args>
class print_info : public ::rexy::debug::print_info<Args...>{
public:
using ::rexy::debug::print_info<Args...>::print_info;
};
template<class... Args>
class print_warn : public ::rexy::debug::print_warn<Args...>{
public:
using ::rexy::debug::print_warn<Args...>::print_warn;
};
template<class... Args>
class print_error : public ::rexy::debug::print_error<Args...>{
public:
using ::rexy::debug::print_error<Args...>::print_error;
};
template<class... Args>
print(Args&&...) -> print<Args&&...>;
template<class... Args>
print_warn(Args&&...) -> print_warn<Args&&...>;
template<class... Args>
print_error(Args&&...) -> print_error<Args&&...>;
template<class... Args>
print_info(Args&&...) -> print_info<Args&&...>;
template<class... Args>
print_succ(Args&&...) -> print_succ<Args&&...>;
}
#else
namespace verbose{
static constexpr inline void print(...){}
static constexpr inline void print_succ(...){}
static constexpr inline void print_info(...){}
static constexpr inline void print_warn(...){}
static constexpr inline void print_error(...){}
}
#endif //LIBREXY_ENABLE_DEBUG_VERBOSE_OUTPUT
}
#else
namespace rexy::debug{
static constexpr inline void print(...){}
static constexpr inline void print_succ(...){}
static constexpr inline void print_info(...){}
static constexpr inline void print_warn(...){}
static constexpr inline void print_error(...){}
namespace verbose{
static constexpr inline void print(...){}
static constexpr inline void print_succ(...){}
static constexpr inline void print_info(...){}
static constexpr inline void print_warn(...){}
static constexpr inline void print_error(...){}
}
}
#endif //LIBREXY_ENABLE_DEBUG_OUTPUT
#endif

View File

@ -1,134 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_UTIL_DEFERRED_HPP
#define REXY_UTIL_DEFERRED_HPP
#include <tuple>
#include <utility> //forward, index_sequence
#include <cstddef> //size_t
#include "compat/standard.hpp"
namespace rexy{
template<class T, class... Args>
class deferred
{
public:
using value_type = T;
private:
std::tuple<Args&&...> m_args;
public:
template<class... FArgs>
constexpr deferred(FArgs&&... args);
REXY_CPP20_CONSTEXPR deferred(const deferred&) = default;
REXY_CPP20_CONSTEXPR deferred(deferred&&) = default;
REXY_CPP20_CONSTEXPR ~deferred(void) = default;
REXY_CPP20_CONSTEXPR deferred& operator=(const deferred&) = default;
REXY_CPP20_CONSTEXPR deferred& operator=(deferred&&) = default;
constexpr value_type value(void);
constexpr operator value_type(void);
private:
template<std::size_t... Is>
constexpr value_type get_value_(std::index_sequence<Is...>);
};
template<class Fn, class... Args>
class deferred_function
{
public:
using ret_t = decltype(std::declval<Fn>()(std::declval<Args>()...));
private:
Fn m_fn;
std::tuple<Args&&...> m_args;
public:
template<class F, class... FArgs>
constexpr deferred_function(F&& f, FArgs&&... args);
constexpr decltype(auto) operator()(void);
constexpr decltype(auto) value(void);
constexpr operator ret_t(void);
private:
template<std::size_t... Is>
constexpr decltype(auto) get_value_(std::index_sequence<Is...>);
};
template<class T, class... Args>
template<class... FArgs>
constexpr deferred<T,Args...>::deferred(FArgs&&... args):
m_args{std::forward<FArgs>(args)...}{}
template<class T, class... Args>
constexpr auto deferred<T,Args...>::value(void) -> value_type{
return get_value_(std::make_index_sequence<sizeof...(Args)>());
}
template<class T, class... Args>
constexpr deferred<T,Args...>::operator value_type(void){
return get_value_(std::make_index_sequence<sizeof...(Args)>());
}
template<class T, class... Args>
template<std::size_t... Is>
constexpr auto deferred<T,Args...>::get_value_(std::index_sequence<Is...>) -> value_type{
return T{std::forward<std::tuple_element_t<Is,decltype(m_args)>>(std::get<Is>(m_args))...};
}
template<class Fn, class... Args>
template<class F, class... FArgs>
constexpr deferred_function<Fn,Args...>::deferred_function(F&& f, FArgs&&... args):
m_fn(std::forward<F>(f)),
m_args{std::forward<FArgs>(args)...}{}
template<class Fn, class... Args>
constexpr decltype(auto) deferred_function<Fn,Args...>::operator()(void){
return get_value_(std::make_index_sequence<sizeof...(Args)>());
}
template<class Fn, class... Args>
constexpr decltype(auto) deferred_function<Fn,Args...>::value(void){
return get_value_(std::make_index_sequence<sizeof...(Args)>());
}
template<class Fn, class... Args>
constexpr deferred_function<Fn,Args...>::operator ret_t(void){
return get_value_(std::make_index_sequence<sizeof...(Args)>());
}
template<class Fn, class... Args>
template<std::size_t... Is>
constexpr decltype(auto) deferred_function<Fn,Args...>::get_value_(std::index_sequence<Is...>){
return std::forward<Fn>(m_fn)(std::forward<std::tuple_element_t<Is,decltype(m_args)>>(std::get<Is>(m_args))...);
}
template<class Fn, class... Args>
deferred_function(Fn&&, Args&&...) -> deferred_function<Fn&&, Args&&...>;
template<class T, class... Args>
deferred<T,Args...> make_deferred(Args&&... args){
return deferred<T,Args...>(std::forward<Args>(args)...);
}
}
#endif

View File

@ -22,40 +22,41 @@
#include "../utility.hpp" //swap #include "../utility.hpp" //swap
#include <type_traits> //nothrow_invocable #include <type_traits> //nothrow_invocable
#include <utility> //pair, forward #include <functional> //less, greater
#include <utility> //pair
#include <iterator> //iterator_traits #include <iterator> //iterator_traits
#include <cstddef> //size_t #include <cstdlib> //size_t
namespace rexy::detail{ namespace rexy::detail{
template<class Iter, class Compare> template<class Iter, class Compare>
constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp) constexpr Iter qs_partition(Iter left, Iter right, const Compare& cmp)
noexcept(std::is_nothrow_invocable<Compare,decltype(*left),decltype(*right)>::value && noexcept(std::is_nothrow_invocable<Compare,decltype(*left),decltype(*right)>::value &&
noexcept(::rexy::swap(*left,*right))) noexcept(swap(*left,*right)))
{ {
auto range = right - left; auto range = right - left;
auto pivot = left + (range / 2); auto pivot = left + (range / 2);
auto value = *pivot; auto value = *pivot;
//move pivot value all the way to the right side to preserve it //move pivot value all the way to the right side to preserve it
::rexy::swap(*pivot, *right); swap(*pivot, *right);
for(auto it = left;it != right;++it){ for(auto it = left;it != right;++it){
if(cmp(*it, value)){ if(cmp(*it, value)){
::rexy::swap(*left, *it); swap(*left, *it);
++left; ++left;
} }
} }
//move pivot value back to proper position //move pivot value back to proper position
::rexy::swap(*left, *right); swap(*left, *right);
return left; return left;
} }
template<class Iter, class Op> template<class Iter, class Op>
constexpr std::pair<std::size_t,size_t> max_suffix(const Iter& needle, std::size_t nlen, const Op& op = Op()){ constexpr std::pair<size_t,size_t> max_suffix(const Iter& needle, size_t nlen, const Op& op = Op()){
using value_type = typename std::iterator_traits<Iter>::value_type; using value_type = typename std::iterator_traits<Iter>::value_type;
std::size_t max_suffix = -1; size_t max_suffix = -1;
std::size_t j = 0; size_t j = 0;
std::size_t k = 1; size_t k = 1;
std::size_t period = 1; size_t period = 1;
value_type a; value_type a;
value_type b; value_type b;
@ -80,23 +81,18 @@ namespace rexy::detail{
} }
return {max_suffix, period}; return {max_suffix, period};
} }
template<class Iter> template<class Iter>
constexpr std::pair<std::size_t,size_t> critical_factorization(const Iter& nstart, const Iter& nend){ constexpr std::pair<size_t,size_t> critical_factorization(const Iter& nstart, const Iter& nend){
auto msuffix = max_suffix(nstart, nend - nstart, []<class T, class U>(T&& left, U&& right) constexpr{ auto msuffix = max_suffix(nstart, nend - nstart, std::less{});
return std::forward<T>(left) < std::forward<U>(right); auto msuffix_rev = max_suffix(nstart, nend - nstart, std::greater{});
});
auto msuffix_rev = max_suffix(nstart, nend - nstart, []<class T, class U>(T&& left, U&& right) constexpr{
return std::forward<T>(left) > std::forward<U>(right);
});
if(msuffix.first < msuffix_rev.first){ if(msuffix.first < msuffix_rev.first){
return msuffix_rev; return msuffix_rev;
} }
return msuffix; return msuffix;
} }
template<class Iter> template<class Iter>
constexpr bool iter_compare(const Iter& left, const Iter& right, std::size_t length){ constexpr bool iter_compare(const Iter& left, const Iter& right, size_t length){
for(std::size_t i = 0;i < length;++i){ for(size_t i = 0;i < length;++i){
if(left[i] != right[i]) if(left[i] != right[i])
return false; return false;
} }

View File

@ -0,0 +1,55 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_BINARY_STRING_CONV_HPP
#define REXY_BINARY_STRING_CONV_HPP
#include "rexy/string_base.hpp"
#include "rexy/binary_base.hpp"
#include <cstring> //memcpy
namespace rexy{
template<class Str, detail::enable_if_concrete_string<Str> = 0>
auto binary_to_string(const binary_base& b)
noexcept(std::is_nothrow_constructible<Str, decltype(b.size())>::value)
{
Str s(b.size()+1);
s.append(b.get(), b.size());
return s;
}
template<class Al, class Str, detail::enable_if_concrete_string<Str> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Str::allocator_type>::value,int> = 0>
auto binary_to_string(basic_binary<Al>&& b)noexcept{
return Str(rexy::steal(b.release()), b.size());
}
template<class Bin, detail::enable_if_binary<Bin> = 0>
auto string_to_binary(const string_base<char>& s)
noexcept(std::is_nothrow_constructible<Bin, decltype(s.length())>::value &&
noexcept(std::decay_t<Bin>::allocator_type::allocate(0)))
{
Bin b(s.length()+1);
b.append(s.get(), s.length()+1);
return b;
}
template<class Al, class Bin, detail::enable_if_binary<Bin> = 0, std::enable_if_t<std::is_same<std::decay_t<Al>,typename Bin::allocator_type>::value,int> = 0>
auto string_to_binary(basic_string<char,Al>&& s)noexcept{
return Bin(rexy::steal(s.release()), s.length());
}
} //namespace rexy
#endif

View File

@ -1,26 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LIBREXY_ENABLE_DEBUG_LEVEL
#define LIBREXY_ENABLE_DEBUG_LEVEL 0
#endif
#ifndef LIBREXY_ENABLE_COLOR_DEBUG
#define LIBREXY_ENABLE_COLOR_DEBUG 1
#endif

View File

@ -1,105 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_ARG_STORE_HPP
#define REXY_DETAIL_FORMAT_ARG_STORE_HPP
#include <cstddef> //size_t
#include "basic_types.hpp" //arg_info
#include "storage.hpp" //stored_type
#include "named_args.hpp" //count_named_args
#include "../../string_view.hpp"
namespace rexy::fmt::detail{
//Implementation of argument storage, erasing the need of passing around a parameter pack. Used in
//constructor of basic_format_args
template<class Context, class... Args>
class basic_format_arg_store
{
public:
using char_type = typename Context::char_type;
public:
static constexpr std::size_t num_args = sizeof...(Args);
static constexpr std::size_t num_named_args = count_named_args_v<Args...>;
struct format_data
{
friend class basic_format_arg_store;
private:
unsigned char m_data[
(sizeof(arg_info) * num_args) +
(sizeof(basic_string_view<char_type>) * num_named_args) +
(sizeof(stored_type_t<Args,Context>) + ...)
] = {};
arg_info* info(void){
return reinterpret_cast<arg_info*>(raw_info());
}
constexpr unsigned char* data(void){
return raw_info() + (sizeof(arg_info) * num_args);
}
constexpr unsigned char* raw_info(void){
return m_data;
}
constexpr const unsigned char* raw_info(void)const{
return m_data;
}
public:
const arg_info* info(void)const{
return reinterpret_cast<const arg_info*>(raw_info());
}
const unsigned char* data(void)const{
return raw_info() + (sizeof(arg_info) * num_args);
}
const unsigned char* raw(void)const{
return m_data;
}
}packed_data;
basic_format_arg_store(Args&&... args);
private:
template<class Arg>
void store_arg(std::size_t argnum, Arg&& arg);
template<NamedArg Arg>
void store_arg(std::size_t argnum, Arg&& arg);
template<class... SArgs>
void store_args(SArgs&&... args);
};
//Specialized for empty parameter pack
template<class Context>
class basic_format_arg_store<Context>
{
public:
static constexpr std::size_t num_args = 0;
};
}
#endif

View File

@ -1,89 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_ARG_STORE_TPP
#define REXY_DETAIL_FORMAT_ARG_STORE_TPP
#include "arg_store.hpp"
#include "storage.hpp"
#include "basic_types.hpp"
#include "../../utility.hpp" //memcpy
#include <utility> //forward
#include <memory> //addressof
#include <cstddef> //size_t
namespace rexy::fmt::detail{
///////////////////////basic_format_arg_store////////////////////////
template<class Context, class... Args>
basic_format_arg_store<Context,Args...>::basic_format_arg_store(Args&&... args){
store_args(std::forward<Args>(args)...);
}
template<class Context, class... Args>
template<class Arg>
void basic_format_arg_store<Context,Args...>::store_arg(std::size_t argnum, Arg&& arg){
using stored_type = stored_type_t<Arg,Context>;
arg_info& ai = packed_data.info()[argnum];
ai.type = map_to_storage_enum_v<stored_type,typename Context::char_type>;
//convert to one of the storable types
stored_type st{std::forward<Arg>(arg)};
//save to the array of data
rexy::memcpy(packed_data.data()+ai.offset, std::addressof(st), sizeof(st));
//setup next entry's offset
if(argnum+1 < num_args){
packed_data.info()[argnum+1].offset = ai.offset + sizeof(st);
}
}
template<class Context, class... Args>
template<NamedArg Arg>
void basic_format_arg_store<Context,Args...>::store_arg(std::size_t argnum, Arg&& arg){
using stored_type = stored_type_t<Arg,Context>;
arg_info& ai = packed_data.info()[argnum];
ai.type = map_to_storage_enum_v<stored_type,typename Context::char_type>;
ai.named = true;
const std::size_t name_size = sizeof(format_string_view<char_type>);
//convert to one of the storable types
stored_type st{std::forward<Arg>(arg).value};
format_string_view<char_type> name{arg.name.c_str(), arg.name.length()};
//save to the array of data
rexy::memcpy(packed_data.data()+ai.offset, std::addressof(name), name_size);
rexy::memcpy(packed_data.data()+ai.offset+name_size, std::addressof(st), sizeof(st));
//setup next entry's offset
if(argnum+1 < num_args){
packed_data.info()[argnum+1].offset = ai.offset + sizeof(st) + name_size;
}
}
template<class Context, class... Args>
template<class... SArgs>
void basic_format_arg_store<Context,Args...>::store_args(SArgs&&... args){
std::size_t argnum = 0;
(store_arg(argnum++, std::forward<SArgs>(args)), ...);
}
}
#endif

View File

@ -1,100 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_BASIC_TYPES_HPP
#define REXY_DETAIL_FORMAT_BASIC_TYPES_HPP
#include <cstddef> //size_t
#include "storage.hpp"
namespace rexy::fmt::detail{
static constexpr std::size_t invalid_arg_index = std::size_t(-1);
template<class Char>
struct format_string_view{
const Char* name;
std::size_t length;
};
struct arg_info{
storage_type type = storage_type::none_t;
std::size_t offset = 0;
bool named = false;
};
enum class alignment : int{
none = 0,
left = '<',
right = '>',
center = '^'
};
enum class presentation{
default_t,
int_t,
char_t,
float_t,
string_t,
ptr_t
};
struct format_specs{
int width = 0;
int precision = 0;
int type = 0;
alignment align = alignment::none;
presentation present = presentation::default_t;
int align_char = ' ';
int sign = 0;
bool locale = false;
bool alt_form = false;
bool zero_fill = false;
};
enum class dyn_type{
none = 0,
index,
string
};
template<class Char>
struct dynamic_format_specs : public format_specs{
union dyn_val{
std::size_t index = invalid_arg_index;
format_string_view<Char> name;
}dyn_width, dyn_precision;
dyn_type width_type = dyn_type::index;
dyn_type precision_type = dyn_type::index;
};
template<class FormatCtx>
constexpr void normalize_dynamic_format_specs(FormatCtx& ctx, dynamic_format_specs<typename FormatCtx::char_type>& specs);
}
namespace rexy{
template<class OutIt>
struct format_to_n_result{
OutIt out;
std::size_t size;
};
}
#endif

View File

@ -1,55 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_BASIC_TYPES_TPP
#define REXY_DETAIL_FORMAT_BASIC_TYPES_TPP
#include "basic_types.hpp"
#include "format_args.hpp"
#include <cstddef> //size_t
namespace rexy::fmt::detail{
template<class FormatCtx>
constexpr void normalize_dynamic_format_specs(FormatCtx& ctx, dynamic_format_specs<typename FormatCtx::char_type>& specs){
std::size_t index = 0;
if(specs.width_type == dyn_type::index){
index = specs.dyn_width.index;
}else{
const auto& name = specs.dyn_width.name;
index = ctx.arg_index(name.name, name.name + name.length);
}
specs.width = ((index != invalid_arg_index)
? visit_format_arg(parse::dynamic_integer_retriever{}, ctx.arg(index))
: specs.width);
if(specs.precision_type == dyn_type::index){
index = specs.dyn_precision.index;
}else{
const auto& name = specs.dyn_precision.name;
index = ctx.arg_index(name.name, name.name + name.length);
}
specs.precision = ((index != invalid_arg_index)
? visit_format_arg(parse::dynamic_integer_retriever{}, ctx.arg(index))
: specs.precision);
}
}
#endif

View File

@ -1,97 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_CONTEXT_HANDLER_HPP
#define REXY_DETAIL_FORMAT_CONTEXT_HANDLER_HPP
#include <cstddef> //size_t
#include "standard_types.hpp"
#include "internal_types.hpp"
#include "format_context.hpp"
#include "parse_context.hpp"
#include "format_args.hpp"
#include "../../string_view.hpp"
#include <locale> //locale
namespace rexy::fmt::detail{
//Holds the format and parse contexts and performs parse+format calls for replacement fields
template<class Char>
struct format_handler
{
public:
using char_type = Char;
using fmt_ctx_t = fmt_context_t<char_type>;
using parse_ctx_t = parse_context_t<char_type>;
using out_it_t = output_iterator_t<char_type>;
using fmt_it_t = typename parse_ctx_t::iterator;
using handle_t = typename basic_format_arg<fmt_ctx_t>::handle;
template<class T>
using fmter_t = typename fmt_ctx_t::template formatter_type<T>;
public:
fmt_ctx_t fmt_ctx;
parse_ctx_t parse_ctx;
public:
format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args);
format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args, const std::locale& l);
constexpr fmt_it_t do_raw(fmt_it_t start, fmt_it_t fin);
constexpr fmt_it_t do_format_spec(fmt_it_t start, fmt_it_t fin, std::size_t id);
constexpr fmt_it_t do_empty_format(fmt_it_t start, fmt_it_t last, std::size_t id);
constexpr std::size_t on_arg_id(void);
constexpr std::size_t on_arg_id(std::size_t i);
constexpr std::size_t on_arg_id(fmt_it_t start, fmt_it_t last);
};
template<class Char>
format_handler(output_iterator_t<Char>, basic_string_view<Char>, basic_format_args<fmt_context_t<Char>>) -> format_handler<Char>;
//Constant-evaluated version of format_handler. Does not perform formatting but will complete a parsing
//pass during compile
template<class Char, class... Args>
class format_checker
{
public:
using char_type = Char;
using parse_ctx_t = parse_context_t<char_type>;
using fmt_it_t = typename parse_ctx_t::iterator;
parse_ctx_t parse_ctx;
consteval format_checker(void) = default;
consteval format_checker(basic_string_view<char_type> fmt, std::size_t numargs = 0);
constexpr fmt_it_t do_raw(fmt_it_t, fmt_it_t last);
constexpr fmt_it_t do_format_spec(fmt_it_t start, fmt_it_t last, std::size_t id);
constexpr void do_empty_format(fmt_it_t, fmt_it_t, std::size_t);
constexpr std::size_t on_arg_id(void);
constexpr std::size_t on_arg_id(std::size_t i);
constexpr std::size_t on_arg_id(fmt_it_t start, fmt_it_t last);
private:
template<std::size_t I, class FArg, class... FArgs>
constexpr fmt_it_t do_format_spec_impl(fmt_it_t start, fmt_it_t last, std::size_t id);
};
}
#endif

View File

@ -1,162 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_CONTEXT_HANDLER_TPP
#define REXY_DETAIL_FORMAT_CONTEXT_HANDLER_TPP
#include "context_handler.hpp"
#include "parse_context.hpp"
#include "format_context.hpp"
#include "formatter.hpp"
#include "format_args.hpp"
#include "named_args.hpp"
#include "format_error.hpp"
#include "../../string_view.hpp"
#include <locale> //locale
#include <cstddef> //size_t
#include <type_traits> //remove_cvref
namespace rexy::fmt::detail{
///////////////////////////////format_handler//////////////////////////////////
template<class Char>
format_handler<Char>::format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args):
fmt_ctx(args, output),
parse_ctx(fmt){}
template<class Char>
format_handler<Char>::format_handler(out_it_t output, basic_string_view<char_type> fmt, basic_format_args<fmt_ctx_t> args, const std::locale& l):
fmt_ctx(args, output, l),
parse_ctx(fmt){}
template<class Char>
constexpr auto format_handler<Char>::do_raw(fmt_it_t start, fmt_it_t fin) -> fmt_it_t{
for(auto it = start;it != fin;++it){
fmt_ctx.out() = *it;
}
return fin;
}
template<class Char>
constexpr auto format_handler<Char>::do_format_spec(fmt_it_t start, fmt_it_t fin, std::size_t id) -> fmt_it_t{
parse_ctx.advance_to(start);
const auto arg = fmt_ctx.arg(id);
format_specs specs;
visit_format_arg(format::arg_formatter<fmt_ctx_t,parse_ctx_t,format_specs>{fmt_ctx, parse_ctx, specs}, arg);
return parse_ctx.begin();
}
template<class Char>
constexpr auto format_handler<Char>::do_empty_format(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
parse_ctx.advance_to(start);
const auto arg = fmt_ctx.arg(id);
visit_format_arg(format::empty_formatter<fmt_ctx_t,parse_ctx_t>{fmt_ctx, parse_ctx}, arg);
return parse_ctx.begin();
}
template<class Char>
constexpr std::size_t format_handler<Char>::on_arg_id(void){
return parse_ctx.next_arg_id();
}
template<class Char>
constexpr std::size_t format_handler<Char>::on_arg_id(std::size_t i){
parse_ctx.check_arg_id(i);
return i;
}
template<class Char>
constexpr std::size_t format_handler<Char>::on_arg_id(fmt_it_t start, fmt_it_t last){
const auto id = fmt_ctx.arg_index(start, last);
parse_ctx.check_arg_id(id);
return id;
}
///////////////////////////////format_checker//////////////////////////////////
template<class Char, class... Args>
consteval format_checker<Char,Args...>::format_checker(basic_string_view<char_type> fmt, std::size_t numargs):
parse_ctx(fmt, numargs){}
template<class Char, class... Args>
constexpr auto format_checker<Char,Args...>::do_raw(fmt_it_t, fmt_it_t last) -> fmt_it_t{
return last;
}
template<class Char, class... Args>
constexpr auto format_checker<Char,Args...>::do_format_spec(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
parse_ctx.advance_to(start);
if constexpr(sizeof...(Args)){
return do_format_spec_impl<0,Args...>(start, last, id);
}else{
REXY_THROW_FORMAT_ERROR("Missing argument");
return start;
}
}
template<class Char, class... Args>
constexpr void format_checker<Char,Args...>::do_empty_format(fmt_it_t, fmt_it_t, std::size_t){/*nothing to parse and the checker doesn't format so just return*/}
template<class Char, class... Args>
template<std::size_t I, class FArg, class... FArgs>
constexpr auto format_checker<Char,Args...>::do_format_spec_impl(fmt_it_t start, fmt_it_t last, std::size_t id) -> fmt_it_t{
if(I == id){
using fmt_ctx_t = fmt_context_t<Char>;
using base_type = std::remove_cvref_t<FArg>;
using stored_type = stored_type_t<base_type,fmt_ctx_t>;
if constexpr(Handle<stored_type,fmt_ctx_t>){
using fmter_t = typename fmt_ctx_t::template formatter_type<base_type>;
fmter_t fmter{};
return fmter.parse(parse_ctx);
}else{
dynamic_format_specs<Char> specs{};
format_specs_checker<cx_format_specs_handler<parse_ctx_t,Args...>> handler{
cx_format_specs_handler<parse_ctx_t,Args...>{parse_ctx, specs},
detail::map_to_storage_enum_v<stored_type,Char>
};
return parse::perform_standard_parse(start, last, handler);
}
}else{
if constexpr(sizeof...(FArgs) > 0){
return do_format_spec_impl<I+1,FArgs...>(start, last, id);
}
}
REXY_THROW_FORMAT_ERROR("Missing argument");
}
template<class Char, class... Args>
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(void){
return parse_ctx.next_arg_id();
}
template<class Char, class... Args>
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(std::size_t i){
if(i > sizeof...(Args)){
REXY_THROW_FORMAT_ERROR("Arg index out of bounds");
}
parse_ctx.check_arg_id(i);
return i;
}
template<class Char, class... Args>
constexpr std::size_t format_checker<Char,Args...>::on_arg_id(fmt_it_t start, fmt_it_t last){
const std::size_t id = find_static_named_arg_id<fmt_it_t, Args...>(start, last);
if(id == invalid_arg_index){
REXY_THROW_FORMAT_ERROR("No such named arg");
}
return on_arg_id(id);
}
}
#endif

View File

@ -1,130 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_ARGS_HPP
#define REXY_DETAIL_FORMAT_FORMAT_ARGS_HPP
#include <cstddef> //size_t
#include <variant> //monostate
#include "storage.hpp" //storage_type
#include "basic_types.hpp" //arg_info
#include "arg_store.hpp"
#include "traits.hpp"
#include "../../string_view.hpp"
namespace rexy::fmt{
//Type erasure of single argument.
//Context is an instantiation of 'basic_format_context'
template<class Context>
class basic_format_arg
{
public:
using char_type = typename Context::char_type;
public:
//Handles call to formatter for a user defined type
//type erase the user defined values
class handle
{
public:
using format_ptr_t = void(handle::*)(basic_format_parse_context<char_type>&, Context&)const;
public:
const void* m_data;
format_ptr_t m_format_impl;
public:
template<class T>
explicit handle(T&& t);
template<class T>
void format_impl(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const;
void format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const;
};
union{
std::monostate none_v = {};
bool bool_v;
char_type char_v;
int int_v;
unsigned int uint_v;
long long long_long_v;
unsigned long long ulong_long_v;
float float_v;
double double_v;
long double long_double_v;
const char_type* char_ptr_v;
basic_string_view<char_type> string_v;
const void* ptr_v;
handle custom_v;
};
detail::storage_type active_member = detail::storage_type::none_t;
//initialize std::variant equivalent to std::monostate
basic_format_arg(void)noexcept{}
explicit basic_format_arg(bool b)noexcept;
explicit basic_format_arg(char_type b)noexcept;
explicit basic_format_arg(int b)noexcept;
explicit basic_format_arg(unsigned int b)noexcept;
explicit basic_format_arg(long long b)noexcept;
explicit basic_format_arg(unsigned long long b)noexcept;
explicit basic_format_arg(float b)noexcept;
explicit basic_format_arg(double b)noexcept;
explicit basic_format_arg(long double b)noexcept;
explicit basic_format_arg(const char_type* b)noexcept;
explicit basic_format_arg(basic_string_view<char_type> b)noexcept;
explicit basic_format_arg(const void* b)noexcept;
explicit basic_format_arg(const handle b)noexcept;
detail::storage_type type(void)const;
explicit operator bool(void)const noexcept;
};
//Holds list of arguments, erasing concrete types.
//Context is an instantiation of 'basic_format_context'
template<class Context>
class basic_format_args
{
public:
using char_type = detail::extract_char_type_from_context_t<Context>;
private:
//TODO less pointers
const detail::arg_info* m_info = nullptr;
const unsigned char* m_data = nullptr;
const std::size_t m_num_args = 0;
public:
basic_format_args(void)noexcept = default;
constexpr basic_format_args(const detail::basic_format_arg_store<Context>& store)noexcept;
template<class... Args>
basic_format_args(const detail::basic_format_arg_store<Context,Args...>& store)noexcept;
basic_format_arg<Context> get(std::size_t i)const noexcept;
basic_format_arg<Context> get(const char_type* first, const char_type* last)const;
std::size_t get_index(const char_type* first, const char_type* last)const;
};
//Visitor for basic_format_arg
template<class Fun, class Context>
decltype(auto) visit_format_arg(Fun&& fun, const basic_format_arg<Context>& arg);
}
#endif

View File

@ -1,236 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_ARGS_TPP
#define REXY_DETAIL_FORMAT_FORMAT_ARGS_TPP
#include "format_args.hpp"
#include "basic_types.hpp" //format_string_view
#include "standard_types.hpp"
#include "parse_context.hpp"
#include "format_context.hpp"
#include "storage.hpp"
#include "arg_store.hpp"
#include "format_error.hpp"
#include "../../string_view.hpp"
#include <utility> //forward
#include <type_traits> //remove_cvref, add_lvalue_reference, add_pointer, add_const, conditional
#include <cstddef> //size_t
#include <memory> //addressof
namespace rexy::fmt{
/////////////////////////////basic_format_arg::handle//////////////////////////////
template<class Context>
template<class T>
basic_format_arg<Context>::handle::handle(T&& t):
m_data(std::addressof(t)),
m_format_impl(&handle::format_impl<std::remove_cvref_t<T>>){}
template<class Context>
template<class T>
void basic_format_arg<Context>::handle::format_impl(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const{
using value_type = std::remove_cvref_t<T>;
using formatter_t = typename Context::template formatter_type<value_type>;
using qualified_type = std::conditional_t<detail::has_const_formatter<value_type,Context>,
std::add_const_t<value_type>,
value_type>;
using reference_type = std::add_lvalue_reference_t<qualified_type>;
using pointer_type = std::add_pointer_t<qualified_type>;
using const_pointer_type = std::add_pointer_t<std::add_const_t<qualified_type>>;
reference_type ref = *const_cast<pointer_type>(reinterpret_cast<const_pointer_type>(m_data));
formatter_t fmt;
parse_ctx.advance_to(fmt.parse(parse_ctx));
format_ctx.advance_to(fmt.format(ref, format_ctx));
}
template<class Context>
void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx)const{
//Pretty epic gamer moment here
(this->*m_format_impl)(parse_ctx, format_ctx);
}
///////////////////////////////basic_format_arg////////////////////////////////
template<class Context>
basic_format_arg<Context>::basic_format_arg(bool b)noexcept:
bool_v(b),
active_member(detail::storage_type::bool_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(char_type b)noexcept:
char_v(b),
active_member(detail::storage_type::char_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(int b)noexcept:
int_v(b),
active_member(detail::storage_type::int_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(unsigned int b)noexcept:
uint_v(b),
active_member(detail::storage_type::uint_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(long long b)noexcept:
long_long_v(b),
active_member(detail::storage_type::long_long_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(unsigned long long b)noexcept:
ulong_long_v(b),
active_member(detail::storage_type::ulong_long_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(float b)noexcept:
float_v(b),
active_member(detail::storage_type::float_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(double b)noexcept:
double_v(b),
active_member(detail::storage_type::double_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(long double b)noexcept:
long_double_v(b),
active_member(detail::storage_type::long_double_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(const char_type* b)noexcept:
char_ptr_v(b),
active_member(detail::storage_type::char_ptr_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type> b)noexcept:
string_v(b),
active_member(detail::storage_type::string_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(const void* b)noexcept:
ptr_v(b),
active_member(detail::storage_type::ptr_t){}
template<class Context>
basic_format_arg<Context>::basic_format_arg(const handle b)noexcept:
custom_v(b),
active_member(detail::storage_type::custom_t){}
template<class Context>
detail::storage_type basic_format_arg<Context>::type(void)const{
return active_member;
}
template<class Context>
basic_format_arg<Context>::operator bool(void)const noexcept{
return active_member != detail::storage_type::none_t;
}
///////////////////////////////basic_format_args////////////////////////////////
template<class Context>
constexpr basic_format_args<Context>::basic_format_args(const detail::basic_format_arg_store<Context>&)noexcept{}
template<class Context>
template<class... Args>
basic_format_args<Context>::basic_format_args(const detail::basic_format_arg_store<Context,Args...>& store)noexcept:
m_info(store.packed_data.info()),
m_data(store.packed_data.data()),
m_num_args(sizeof...(Args)){}
template<class Context>
basic_format_arg<Context> basic_format_args<Context>::get(std::size_t i)const noexcept{
const bool named = m_info[i].named;
const std::size_t offset = m_info[i].offset + (named ? sizeof(detail::format_string_view<char_type>) : 0);
const unsigned char* const data = m_data + offset;
switch(m_info[i].type){
case detail::storage_type::bool_t:
return basic_format_arg<Context>{*reinterpret_cast<const bool*>(data)};
case detail::storage_type::char_t:
return basic_format_arg<Context>{*reinterpret_cast<const char_type*>(data)};
case detail::storage_type::int_t:
return basic_format_arg<Context>{*reinterpret_cast<const int*>(data)};
case detail::storage_type::uint_t:
return basic_format_arg<Context>{*reinterpret_cast<const unsigned int*>(data)};
case detail::storage_type::long_long_t:
return basic_format_arg<Context>{*reinterpret_cast<const long long*>(data)};
case detail::storage_type::ulong_long_t:
return basic_format_arg<Context>{*reinterpret_cast<const unsigned long long*>(data)};
case detail::storage_type::float_t:
return basic_format_arg<Context>{*reinterpret_cast<const float*>(data)};
case detail::storage_type::double_t:
return basic_format_arg<Context>{*reinterpret_cast<const double*>(data)};
case detail::storage_type::long_double_t:
return basic_format_arg<Context>{*reinterpret_cast<const long double*>(data)};
case detail::storage_type::char_ptr_t:
return basic_format_arg<Context>{*reinterpret_cast<const char_type* const*>(data)};
case detail::storage_type::string_t:
return basic_format_arg<Context>{*reinterpret_cast<const basic_string_view<char_type>*>(data)};
case detail::storage_type::ptr_t:
return basic_format_arg<Context>{reinterpret_cast<const void*>(*reinterpret_cast<const char* const*>(data))};
case detail::storage_type::custom_t:
return basic_format_arg<Context>{*reinterpret_cast<const typename basic_format_arg<Context>::handle*>(data)};
default:
return basic_format_arg<Context>{};
};
}
template<class Context>
basic_format_arg<Context> basic_format_args<Context>::get(const char_type* first, const char_type* last)const{
return get(get_index(first, last));
}
template<class Context>
std::size_t basic_format_args<Context>::get_index(const char_type* first, const char_type* last)const{
for(std::size_t i = 0;i < m_num_args;++i){
if(m_info[i].named){
auto data = reinterpret_cast<const detail::format_string_view<char_type>* const>(m_data + m_info[i].offset);
const std::size_t len = last - first;
if(len == data->length && !rexy::strncmp(data->name, first, len)){
return i;
}
}
}
REXY_THROW_FORMAT_ERROR("Requested named arg does not exist");
}
template<class Fun, class Context>
decltype(auto) visit_format_arg(Fun&& fun, const basic_format_arg<Context>& arg){
switch(arg.type()){
case detail::storage_type::bool_t:
return std::forward<Fun>(fun)(arg.bool_v);
case detail::storage_type::char_t:
return std::forward<Fun>(fun)(arg.char_v);
case detail::storage_type::int_t:
return std::forward<Fun>(fun)(arg.int_v);
case detail::storage_type::uint_t:
return std::forward<Fun>(fun)(arg.uint_v);
case detail::storage_type::long_long_t:
return std::forward<Fun>(fun)(arg.long_long_v);
case detail::storage_type::ulong_long_t:
return std::forward<Fun>(fun)(arg.ulong_long_v);
case detail::storage_type::float_t:
return std::forward<Fun>(fun)(arg.float_v);
case detail::storage_type::double_t:
return std::forward<Fun>(fun)(arg.double_v);
case detail::storage_type::long_double_t:
return std::forward<Fun>(fun)(arg.long_double_v);
case detail::storage_type::char_ptr_t:
return std::forward<Fun>(fun)(arg.char_ptr_v);
case detail::storage_type::string_t:
return std::forward<Fun>(fun)(arg.string_v);
case detail::storage_type::ptr_t:
return std::forward<Fun>(fun)(arg.ptr_v);
case detail::storage_type::custom_t:
return std::forward<Fun>(fun)(arg.custom_v);
default:
REXY_THROW_FORMAT_ERROR("Invalid format_arg storage_type");
};
}
}
#endif

View File

@ -1,77 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_CONTEXT_HPP
#define REXY_DETAIL_FORMAT_FORMAT_CONTEXT_HPP
#include <type_traits> //remove_cvref, declval, integral_constant, void_t
#include <cstddef> //size_t
#include <locale> //locale
#include "standard_types.hpp" //basic_format_args, formatter
namespace rexy::fmt{
namespace detail{
//type trait used for properly cv-qualifying the argument to a call to formatter<type>::format
template<class T, class Context, class = void>
struct is_formatter_const : public std::false_type{};
template<class T, class Context>
struct is_formatter_const<T,Context,std::void_t<
decltype(std::declval<typename Context::template formatter_type<std::remove_cvref_t<T>>>().format(std::declval<const T&>(), std::declval<Context>()))
>> : public std::true_type{};
template<class T, class Context>
concept has_formatter = requires(typename Context::template formatter_type<std::remove_cvref_t<T>> fmter, T& t, Context& ctx){
fmter.format(t, ctx);
};
template<class T, class Context>
concept has_const_formatter = has_formatter<const std::remove_cvref_t<T>, Context>;
}
//Holds the arguments passed to calls to 'format' or 'vformat' in type erasing structure.
//Additionally holds the iterator where output is written.
template<class OutIt, class Char>
class basic_format_context
{
public:
using iterator = OutIt;
using char_type = Char;
template<class T>
using formatter_type = formatter<T, Char>;
private:
basic_format_args<basic_format_context> m_fmt_args;
iterator m_outit;
std::locale m_locale;
public:
basic_format_context(basic_format_args<basic_format_context> fmt_args, iterator outit);
basic_format_context(basic_format_args<basic_format_context> fmt_args, iterator outit, const std::locale& l);
basic_format_arg<basic_format_context> arg(std::size_t id)const;
basic_format_arg<basic_format_context> arg(const char_type* first, const char_type* last)const;
std::size_t arg_index(const char_type* first, const char_type* last)const;
std::locale locale(void);
iterator out(void);
void advance_to(iterator it);
};
}
#endif

View File

@ -1,70 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_CONTEXT_TPP
#define REXY_DETAIL_FORMAT_FORMAT_CONTEXT_TPP
#include "format_context.hpp"
#include "format_args.hpp"
#include <utility> //move
#include <cstddef> //size_t
#include <locale> //locale
namespace rexy::fmt{
///////////////////////////////basic_format_context////////////////////////////////
template<class OutIt, class Char>
basic_format_context<OutIt,Char>::basic_format_context(basic_format_args<basic_format_context> fmt_args, iterator outit):
m_fmt_args(fmt_args),
m_outit(outit){}
template<class OutIt, class Char>
basic_format_context<OutIt,Char>::basic_format_context(basic_format_args<basic_format_context> fmt_args, iterator outit, const std::locale& l):
m_fmt_args(fmt_args),
m_outit(outit),
m_locale(l){}
template<class OutIt, class Char>
auto basic_format_context<OutIt,Char>::arg(std::size_t id)const -> basic_format_arg<basic_format_context>{
return m_fmt_args.get(id);
}
template<class OutIt, class Char>
auto basic_format_context<OutIt,Char>::arg(const char_type* first, const char_type* last)const -> basic_format_arg<basic_format_context>{
return m_fmt_args.get(first, last);
}
template<class OutIt, class Char>
std::size_t basic_format_context<OutIt,Char>::arg_index(const char_type* first, const char_type* last)const{
return m_fmt_args.get_index(first, last);
}
template<class OutIt, class Char>
std::locale basic_format_context<OutIt,Char>::locale(void){
return m_locale;
}
template<class OutIt, class Char>
auto basic_format_context<OutIt,Char>::out(void) -> iterator{
return std::move(m_outit);
}
template<class OutIt, class Char>
void basic_format_context<OutIt,Char>::advance_to(iterator it){
m_outit = std::move(it);
}
}
#endif

View File

@ -1,47 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_ERROR_HPP
#define REXY_DETAIL_FORMAT_FORMAT_ERROR_HPP
#include "../../string_view.hpp"
#include "../../detail/debug_config.hpp"
#define REXY_FORMAT_REAL_STRINGIFY(str) #str
#define REXY_FORMAT_STRINGIFY(str) REXY_FORMAT_REAL_STRINGIFY(str)
#if LIBREXY_ENABLE_DEBUG_LEVEL > 0
#define REXY_THROW_FORMAT_ERROR(errstring) throw format_error{__FILE__ ":" REXY_FORMAT_STRINGIFY(__LINE__) ": " errstring}
#else
#define REXY_THROW_FORMAT_ERROR(errstring) throw format_error{errstring}
#endif
namespace rexy::fmt{
struct format_error{
string_view errstr;
constexpr const char* what(void)const{
return errstr.c_str();
}
};
}
#endif

View File

@ -1,40 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_STRING_HPP
#define REXY_DETAIL_FORMAT_FORMAT_STRING_HPP
#include "../../string_view.hpp"
namespace rexy::fmt::detail{
//Class accepted as an argument to 'format' calls. Will call a constant-evaluated parse of the format string
//to check for correctness.
template<class Char, class... Args>
class basic_format_string
{
public:
basic_string_view<Char> str;
consteval basic_format_string(const Char* f);
consteval basic_format_string(basic_string_view<Char> f);
};
}
#endif

View File

@ -1,43 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMAT_STRING_TPP
#define REXY_DETAIL_FORMAT_FORMAT_STRING_TPP
#include "format_string.hpp"
#include "context_handler.hpp"
#include "parse.hpp"
#include "../../string_view.hpp"
namespace rexy::fmt::detail{
template<class Char, class... Args>
consteval basic_format_string<Char,Args...>::basic_format_string(const Char* f):
basic_format_string(basic_string_view<Char>{f}){}
template<class Char, class... Args>
consteval basic_format_string<Char,Args...>::basic_format_string(basic_string_view<Char> f):
str(f)
{
parse::perform_parse(format_checker<Char, Args...>{f, sizeof...(Args)}, str);
}
}
#endif

View File

@ -1,178 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMATTER_HPP
#define REXY_DETAIL_FORMAT_FORMATTER_HPP
#include <cstddef> //std::size_t, nullptr_t
#include <variant> //monostate
#include <locale> //locale
#include <type_traits> //remove_cvref
#include <utility> //forward
#include "basic_types.hpp" //format_specs
#include "internal_types.hpp"
#include "standard_types.hpp" //basic_parse_context
#include "specs_handler.hpp" //format_specs_checker
#include "traits.hpp"
#include "../../string.hpp"
#include "../../string_view.hpp"
#include "../../allocator.hpp"
namespace rexy::fmt{
namespace detail{
namespace format{
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const void* t, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const void* t, OutIt out);
template<class Char, class OutIt>
requires(!UTF8_String<Char>)
constexpr OutIt perform_standard_format(const Char* c, OutIt out, const format_specs& specs, const std::locale& loc);
template<UTF8_String Char, class OutIt>
requires(UTF8_String<Char>)
constexpr OutIt perform_standard_format(const Char* c, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const Char* c, OutIt out);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(basic_string_view<std::type_identity_t<Char>> str, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(basic_string_view<std::type_identity_t<Char>> str, OutIt out);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(Char b, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(Char b, OutIt out);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(bool b, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(bool b, OutIt out);
template<class Char, class OutIt, Integral T>
constexpr OutIt perform_standard_format(T b, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt, Arithmetic T>
constexpr OutIt perform_standard_format(T b, OutIt out);
template<class Char, class OutIt, Floating T>
constexpr OutIt perform_standard_format(T f, OutIt out, const format_specs& specs, const std::locale& loc);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(std::monostate, OutIt out, const format_specs&, const std::locale&);
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(std::monostate, OutIt out);
template<class FmtCtx, class ParseCtx, class Specs>
struct arg_formatter{
FmtCtx& fmt_ctx;
ParseCtx& parse_ctx;
const Specs& specs;
template<Handle<FmtCtx> T>
constexpr void operator()(T&& t);
template<class T>
constexpr void operator()(T&& t);
};
template<class FmtCtx, class ParseCtx>
struct empty_formatter{
FmtCtx& fmt_ctx;
ParseCtx& parse_ctx;
template<Handle<FmtCtx> T>
constexpr void operator()(T&& t);
template<class T>
constexpr void operator()(T&& t);
};
}
template<class T, class Char>
class formatter_base
{
public:
using char_type = Char;
using parse_ctx_t = basic_format_parse_context<char_type>;
using fmt_ctx_t = detail::fmt_context_t<char_type>;
using format_spec_t = detail::dynamic_format_specs<char_type>;
using format_spec_handler_t = detail::format_specs_checker<detail::dynamic_format_specs_handler<parse_ctx_t>>;
protected:
format_spec_t specs;
public:
constexpr auto parse(basic_format_parse_context<Char>& ctx) -> decltype(ctx.begin());
template<class U, class FormatContext>
auto format(U&& t, FormatContext& ctx) -> decltype(ctx.out());
};
}
}
namespace rexy{
template<class T, class Char = char>
class formatter;
#define IMPLEMENT_STANDARD_FORMATTER(type) \
template<fmt::detail::Formatter_Char C> \
class formatter<type, C> : public fmt::detail::formatter_base<fmt::detail::stored_type_t<type,fmt::detail::fmt_context_t<C>>, C>{}
IMPLEMENT_STANDARD_FORMATTER(int);
IMPLEMENT_STANDARD_FORMATTER(unsigned int);
IMPLEMENT_STANDARD_FORMATTER(long long);
IMPLEMENT_STANDARD_FORMATTER(unsigned long long);
IMPLEMENT_STANDARD_FORMATTER(bool);
IMPLEMENT_STANDARD_FORMATTER(float);
IMPLEMENT_STANDARD_FORMATTER(double);
IMPLEMENT_STANDARD_FORMATTER(long double);
IMPLEMENT_STANDARD_FORMATTER(std::nullptr_t);
IMPLEMENT_STANDARD_FORMATTER(short);
IMPLEMENT_STANDARD_FORMATTER(unsigned short);
IMPLEMENT_STANDARD_FORMATTER(long);
IMPLEMENT_STANDARD_FORMATTER(unsigned long);
IMPLEMENT_STANDARD_FORMATTER(char);
IMPLEMENT_STANDARD_FORMATTER(unsigned char);
IMPLEMENT_STANDARD_FORMATTER(signed char);
template<fmt::detail::Formatter_Char C>
class formatter<C*,C> : public fmt::detail::formatter_base<const C*,C>{};
template<fmt::detail::Formatter_Char C>
class formatter<const C*,C> : public fmt::detail::formatter_base<const C*,C>{};
template<fmt::detail::Formatter_Char C, std::size_t I>
class formatter<const C[I],C> : public fmt::detail::formatter_base<const C*,C>{};
template<fmt::detail::Formatter_Char C, REXY_ALLOCATOR_CONCEPT A>
class formatter<basic_string<C,A>,C> : public fmt::detail::formatter_base<basic_string_view<C>,C>{};
template<fmt::detail::Formatter_Char C>
class formatter<basic_string_view<C>,C> : public fmt::detail::formatter_base<basic_string_view<C>,C>{};
template<class T, fmt::detail::Formatter_Char C>
class formatter<T*,C> : public fmt::detail::formatter_base<const void*,C>{};
template<class T, fmt::detail::Formatter_Char C>
class formatter<const T*,C> : public fmt::detail::formatter_base<const void*,C>{};
#undef IMPLEMENT_STANDARD_FORMATTER
}
#endif

View File

@ -1,665 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_FORMATTER_TPP
#define REXY_DETAIL_FORMAT_FORMATTER_TPP
#include "formatter.hpp"
#include "basic_types.hpp"
#include "internal_types.hpp"
#include "standard_types.hpp"
#include "parse_context.hpp"
#include "format_context.hpp"
#include "format_args.hpp"
#include "parse.hpp"
#include "utf_iterator.hpp"
#include "../../utility.hpp" //abs, memcpy
#include <type_traits> //remove_cvref
#include <utility> //forward, move
#include <cstddef> //size_t
#include <algorithm> //max
#include <cmath> //signbit
#include <charconv> //to_chars
#include <cctype> //toupper
#include <cstdint> //uintptr_t
#include <locale> //locale
#include <variant> //monostate
#include <limits>
namespace rexy::fmt::detail{
template<class T, class Char>
constexpr auto formatter_base<T,Char>::parse(basic_format_parse_context<Char>& ctx) -> decltype(ctx.begin()){
using stored_type = detail::stored_type_t<std::remove_cvref_t<T>,fmt_ctx_t>;
return detail::parse::perform_standard_parse(
ctx.begin(),
ctx.end(),
format_spec_handler_t{
detail::dynamic_format_specs_handler<parse_ctx_t>{ctx, specs},
detail::map_to_storage_enum_v<stored_type,char_type>
}
);
}
template<class T, class Char>
template<class U, class FormatContext>
auto formatter_base<T,Char>::format(U&& t, FormatContext& ctx) -> decltype(ctx.out()){
normalize_dynamic_format_specs(ctx, specs);
return detail::format::perform_standard_format<Char>(std::forward<U>(t), ctx.out(), specs);
}
namespace format{
template<class Char, class OutIt>
constexpr OutIt perform_format_write(const Char* c, OutIt out, std::size_t length){
for(std::size_t i = 0;i < length;++i){
*out++ = c[i];
}
return std::move(out);
}
template<class OutIt, class Outputer>
constexpr OutIt perform_format_write_aligned(OutIt out, int width, const format_specs& specs, alignment default_align, Outputer&& outputer){
const int fill_amount = std::max(specs.width - width, 0);
int left_fill_amount = fill_amount;
int right_fill_amount = fill_amount;
const alignment align = specs.align == alignment::none ? default_align : specs.align;
switch(align){
case alignment::center:
left_fill_amount /= 2;
[[fallthrough]];
case alignment::right:
for(std::size_t i = 0;i < left_fill_amount;++i){
*out++ = specs.align_char;
}
right_fill_amount -= left_fill_amount;
[[fallthrough]];
case alignment::left:
out = outputer(std::move(out));
for(std::size_t i = 0;i < right_fill_amount;++i){
*out++ = specs.align_char;
}
break;
default:
REXY_THROW_FORMAT_ERROR("Invalid alignment state");
};
return std::move(out);
}
template<class T>
consteval T cxlog10(T t){
return t < 10 ? 1 : 1 + cxlog10(t / 10);
}
template<class OutIt, class T>
constexpr OutIt perform_format_write_sign(OutIt out, int sign, T val){
if(val < 0){
*out++ = '-';
}else if(sign == '+'){
*out++ = '+';
}else if(sign == ' '){
*out++ = ' ';
}
return std::move(out);
}
template<class OutIt, Floating T>
constexpr OutIt perform_format_write_sign(OutIt out, int sign, T val){
if(std::signbit(val)){
*out++ = '-';
}else if(sign == '+'){
*out++ = '+';
}else if(sign == ' '){
*out++ = ' ';
}
return std::move(out);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const void* t, OutIt out, const format_specs& specs, const std::locale& loc){
//2 hexidecimal digits per octet
constexpr std::size_t maxbufflen = sizeof(std::uintptr_t) * (CHAR_BIT / 4.0) + 3; //+2 for '0x', +1 for float rounding truncation
char buff[maxbufflen] = {};
buff[0] = '0';
buff[1] = 'x';
char* buffstart = buff + 2;
char* buffend = buff + maxbufflen;
auto result = std::to_chars(buffstart, buffend, reinterpret_cast<std::uintptr_t>(t), 16);
if(result.ec != std::errc{}){
REXY_THROW_FORMAT_ERROR("Unable to convert pointer type");
}
return perform_standard_format<Char>(buff, out, specs, loc);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const void* t, OutIt out){
//2 hexidecimal digits per octet
constexpr std::size_t maxbufflen = sizeof(std::uintptr_t) * (CHAR_BIT / 4.0) + 4; //+2 for '0x', +1 for float rounding truncation
char buff[maxbufflen] = {};
buff[0] = '0';
buff[1] = 'x';
char* buffstart = buff + 2;
char* buffend = buff + maxbufflen;
auto result = std::to_chars(buffstart, buffend, reinterpret_cast<std::uintptr_t>(t), 16);
if(result.ec != std::errc{}){
REXY_THROW_FORMAT_ERROR("Unable to convert pointer type");
}
const auto bufflen = result.ptr - buff;
return perform_format_write(buff, out, bufflen);
}
static constexpr unsigned int codepoint_fields[] = {
0x1100u, 0x115Fu,
0x2329u, 0x232Au,
0x2E80u, 0x303Eu,
0x3040u, 0xA4CFu,
0xAC00u, 0xD7A3u,
0xF900u, 0xFAFFu,
0xFE10u, 0xFE19u,
0xFE30u, 0xFE6Fu,
0xFF00u, 0xFF60u,
0xFFE0u, 0xFFE6u,
0x1F300u, 0x1F64Fu,
0x1F900u, 0x1F9FFu,
0x20000u, 0x2FFFDu,
0x30000u, 0x3FFFDu
};
constexpr unsigned int estimate_unicode_width(const char32_t c){
unsigned int width = 1;
for(auto field : codepoint_fields){
if(c < field){
return width;
}
//flip between 1 and 2
width ^= 3u;
}
return width;
}
constexpr unsigned int estimate_unicode_string_width(const char* first, const char* last){
unsigned int width = 0;
for(utf8_iterator<char> it{first, last};it.valid();++it){
const auto codepoint = *it;
width += estimate_unicode_width(codepoint);
}
return width;
}
template<class Char, class OutIt>
requires(!UTF8_String<Char>)
constexpr OutIt perform_standard_format(const Char* c, OutIt out, const format_specs& specs, const std::locale& loc){
const basic_string_view<Char> str{c};
std::size_t est_width = 0;
std::size_t print_cnt = 0;
if(specs.precision > 0){
est_width = std::min<std::size_t>(str.length(), specs.precision);
print_cnt = est_width;
}else{
est_width = str.length();
print_cnt = str.length();
}
const auto outputter = [&](OutIt o){
for(std::size_t i = 0;i < print_cnt;++i){
*o++ = str[i];
}
return std::move(o);
};
return perform_format_write_aligned(std::move(out), est_width, specs, alignment::left, outputter);
}
template<UTF8_String Char, class OutIt>
requires(UTF8_String<Char>)
constexpr OutIt perform_standard_format(const Char* c, OutIt out, const format_specs& specs, const std::locale& loc){
const basic_string_view<Char> str{c};
std::size_t est_width = 0;
std::size_t print_cnt = 0;
if(specs.precision > 0){
for(utf8_iterator<Char> it{str.begin(), str.end()};it.valid();++it){
const auto ch_width = estimate_unicode_width(*it);
if(ch_width + est_width > specs.precision){
break;
}
print_cnt += it.byte_count();
est_width += ch_width;
}
}else{
est_width = estimate_unicode_string_width(str.cbegin(), str.cend());
print_cnt = str.length();
}
const auto outputter = [&](OutIt o){
for(std::size_t i = 0;i < print_cnt;++i){
*o++ = str[i];
}
return std::move(o);
};
return perform_format_write_aligned(std::move(out), est_width, specs, alignment::left, outputter);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(const Char* c, OutIt out){
for(const Char* i = c;*i;++i){
*out++ = *i;
}
return std::move(out);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(basic_string_view<std::type_identity_t<Char>> str, OutIt out, const format_specs& specs, const std::locale& loc){
return perform_standard_format<Char>(str.c_str(), std::move(out), specs, loc);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(basic_string_view<std::type_identity_t<Char>> str, OutIt out){
return perform_standard_format(str.c_str(), std::move(out));
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(Char b, OutIt out, const format_specs& specs, const std::locale& loc){
if(specs.present == presentation::int_t){
return perform_standard_format<Char>(static_cast<int>(b), std::move(out), specs, loc);
}
const auto outputter = [=](OutIt o){
*o++ = b;
return std::move(o);
};
return perform_format_write_aligned(std::move(out), 1, specs, alignment::left, outputter);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(Char b, OutIt out){
*out++ = b;
return std::move(out);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(bool b, OutIt out, const format_specs& specs, const std::locale& loc){
switch(specs.present){
case presentation::default_t:
case presentation::string_t:
break;
case presentation::int_t:
case presentation::char_t:
return perform_standard_format<Char>(static_cast<unsigned char>(b), std::move(out), specs, loc);
default:
REXY_THROW_FORMAT_ERROR("Invalid type argument for bool");
};
if(specs.locale){
const auto& facet = std::use_facet<std::numpunct<Char>>(loc);
const auto word = b ? facet.truename() : facet.falsename();
format_specs copy_specs = specs;
copy_specs.locale = false;
return perform_standard_format<Char>(
word.c_str(),
std::move(out),
copy_specs,
loc
);
}
return perform_standard_format<Char>(b ? "true" : "false", std::move(out), specs, loc);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(bool b, OutIt out){
return perform_standard_format<Char>(b ? "true" : "false", std::move(out));
}
template<class Char, class OutIt>
constexpr OutIt perform_localized_integer_write(OutIt out, const char* start, const char* last, const std::locale& loc){
const auto& facet = std::use_facet<std::numpunct<Char>>(loc);
const int group_size = int(facet.grouping()[0]);
const Char sep = facet.thousands_sep();
const int len = int(last - start);
if(group_size != 0){
int write_count = (len-1) % group_size;
*out++ = *start++;
while(true){
for(;write_count > 0;--write_count){
*out++ = *start++;
}
if(start == last){
break;
}
*out++ = sep;
write_count = std::min(group_size, int(last - start));
}
return std::move(out);
}
return perform_format_write(start, std::move(out), len);
}
template<class Char, class OutIt, Integral T>
constexpr OutIt perform_standard_format(T b, OutIt out, const format_specs& specs, const std::locale& loc){
constexpr std::size_t maxbufflen = rexy::max(
std::numeric_limits<long long>::digits + 3, //add 1 for sign bit, 2 for prefix
std::numeric_limits<unsigned long long>::digits + 3
);
if(specs.present == presentation::char_t){
return perform_standard_format<Char>(static_cast<Char>(b), std::move(out), specs, loc);
};
int base = 10;
int total_width = 0;
const bool should_zero_fill = specs.zero_fill && specs.align == alignment::none;
bool to_upper = false;
char buff[maxbufflen] = {};
char* buffstart = buff;
char* buffend = buff + maxbufflen;
string_view prefix = "";
switch(specs.type){
case 'b':
prefix = "0b";
base = 2;
break;
case 'B':
prefix = "0B";
base = 2;
break;
case 'o':
prefix = b == 0 ? "" : "0";
base = 8;
break;
case 'x':
prefix = "0x";
base = 16;
break;
case 'X':
prefix = "0X";
to_upper = true;
base = 16;
break;
default:
break;
};
total_width += prefix.length();
auto result = std::to_chars(buffstart, buffend, b, base);
if(result.ec != std::errc{}){
REXY_THROW_FORMAT_ERROR("Unable to convert integral type");
}
buffend = result.ptr;
if(b < 0){
++buffstart;
total_width += 1;
}else if(specs.sign != 0){
total_width += 1;
}
const auto bufflen = buffend - buffstart;
total_width += bufflen;
if(to_upper){
for(auto it = buffstart;it != buffend;++it){
*it = std::toupper(*it);
}
}
const auto outputter = [&](OutIt o) -> OutIt{
if(specs.alt_form){
o = perform_format_write_sign(std::move(o), specs.sign, b);
o = perform_format_write(prefix.data(), std::move(o), prefix.length());
}else{
o = perform_format_write(prefix.data(), std::move(out), prefix.length());
o = perform_format_write_sign(std::move(o), specs.sign, b);
}
if(should_zero_fill && specs.width > total_width){
const int fill_width = specs.width - total_width;
for(int i = 0;i < fill_width;++i){
*o++ = '0';
}
}
if(specs.locale){
const auto& facet = std::use_facet<std::numpunct<Char>>(loc);
const int group_size = facet.grouping()[0];
const Char sep = facet.thousands_sep();
return perform_localized_integer_write<Char>(std::move(o), buffstart, buffend, loc);
}
return perform_format_write(buffstart, std::move(o), bufflen);
};
if(should_zero_fill){
return outputter(std::move(out));
}
return perform_format_write_aligned(std::move(out), total_width, specs, alignment::right, outputter);
}
//////////////////////////////////////////////DONE///////////////////////////////////////////////
template<class Char, class OutIt, Arithmetic T>
constexpr OutIt perform_standard_format(T b, OutIt out){
using limits = std::numeric_limits<long double>;
constexpr auto maxexp = limits::max_exponent10; //this is a constant expression but using limits::max_exponent10 directly isn't?
//long double will be the longest type possible, so operate on that.
//+4 for ones' place digit, decimal point, and 'e+' in scientific mode
//maximum buffer length is the maximum significant digits plus maximum length of exponent
constexpr std::size_t maxbufflen = 4 + limits::max_digits10 + cxlog10(maxexp);
char buff[maxbufflen] = {};
char* buffend = buff + maxbufflen;
auto result = std::to_chars(buff, buffend, b);
if(result.ec != std::errc{}){
REXY_THROW_FORMAT_ERROR("Unable to convert arithmetic type");
}
const auto bufflen = result.ptr - buff;
return perform_format_write(buff, std::move(out), bufflen);
}
//TODO
template<class Char, class OutIt, Floating T>
constexpr OutIt perform_standard_format(T f, OutIt out, const format_specs& specs, const std::locale& loc){
using limits = std::numeric_limits<T>;
//max number of post-decimal digits is same as the inverted smallest radix exponent
constexpr int max_precision = rexy::abs(limits::min_exponent);
//max number of leading digits is same as biggest decimal exponent
constexpr int max_significants = limits::max_exponent10;
//+4 for ones' place digit, decimal point, and 'e+' in scientific mode
//maximum buffer length is the maximum significant digits plus maximum precision because the
//user can request any precision. So you can take the longest number with no decimal and add on
//the longest decimal trail allowed.
constexpr int maxbufflen = max_precision + max_significants + 4;
char buff[maxbufflen] = {};
char* buffstart = buff;
char* buffend = buff + maxbufflen;
const bool supplied_precision = specs.precision > 0;
const bool is_infinity = f == std::numeric_limits<T>::infinity() || f == -std::numeric_limits<T>::infinity();
const bool is_nan = (f != f);
const bool is_integer_representable = (static_cast<T>(static_cast<long long>(f)) == f) && !is_infinity && !is_nan;
const bool should_zero_fill = specs.zero_fill && specs.align == alignment::none;
std::chars_format fmt = std::chars_format::general;
bool to_upper = false;
bool manual_precision = supplied_precision;
bool trailing_dot = false;
std::size_t total_width = 0;
//TODO handle any other modes and formatting options
std::to_chars_result result{};
switch(specs.type){
case 'A':
to_upper = true;
[[fallthrough]];
case 'a':
fmt = std::chars_format::hex;
break;
case 'E':
to_upper = true;
[[fallthrough]];
case 'e':
fmt = std::chars_format::scientific;
manual_precision = true;
break;
case 'F':
to_upper = true;
[[fallthrough]];
case 'f':
fmt = std::chars_format::fixed;
manual_precision = true;
break;
case 'G':
to_upper = true;
[[fallthrough]];
case 'g':
manual_precision = true;
if(specs.alt_form){
//keep trailing zeros
fmt = std::chars_format::fixed;
}
break;
default:
trailing_dot = is_integer_representable && !supplied_precision && specs.alt_form;
break;
};
//manually handle nan and inf since some compilers (msvc) output something other than the desired values in 'to_chars'
if(is_nan){
result.ptr = buffstart + 3;
rexy::memcpy(buffstart, "nan", 3);
}else if(is_infinity){
result.ptr = buffstart + 3;
rexy::memcpy(buffstart, "inf", 3);
}else if(manual_precision){
const int precision = supplied_precision ? specs.precision : 6;
result = std::to_chars(buffstart, buffend, f, fmt, precision);
}else{
result = std::to_chars(buffstart, buffend, f, fmt);
}
if(result.ec != std::errc{}){
REXY_THROW_FORMAT_ERROR("Unable to convert floating type");
}
buffend = result.ptr;
//exclude negative sign automatically put there
if(buffstart[0] == '-'){
++buffstart;
++total_width;
}else if(specs.sign != 0){
++total_width;
}
if(trailing_dot){
++total_width;
}
const auto bufflen = buffend - buffstart;
total_width += bufflen;
if(to_upper){
for(auto it = buffstart;it != buffend;++it){
*it = std::toupper(*it);
}
}
const auto outputter = [&](OutIt o){
Char radix_char = '.';
o = perform_format_write_sign(std::move(o), specs.sign, f);
if(should_zero_fill && specs.width > total_width && !(is_infinity || is_nan)){
const int fill_width = specs.width - total_width;
for(int i = 0;i < fill_width;++i){
*o++ = '0';
}
}
if(specs.locale){
const auto& facet = std::use_facet<std::numpunct<Char>>(loc);
const int group_size = facet.grouping()[0];
radix_char = facet.decimal_point();
string_view buff_view{buffstart, buffend};
const auto radix_pos = buff_view.find_first_of('.');
if(radix_pos != string_view::npos){
buff[radix_pos] = radix_char;
o = perform_localized_integer_write<Char>(std::move(o), buffstart, buffstart + radix_pos, loc);
buffstart += radix_pos;
}
}
o = perform_format_write(buffstart, std::move(o), bufflen);
if(trailing_dot){
*o++ = radix_char;
}
return std::move(o);
};
if(should_zero_fill){
return outputter(std::move(out));
}
return perform_format_write_aligned(std::move(out), total_width, specs, alignment::right, outputter);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(std::monostate, OutIt out, const format_specs&, const std::locale&){
return std::move(out);
}
template<class Char, class OutIt>
constexpr OutIt perform_standard_format(std::monostate, OutIt out){
return std::move(out);
}
template<class FmtCtx, class ParseCtx, class Specs>
template<Handle<FmtCtx> T>
constexpr void arg_formatter<FmtCtx,ParseCtx,Specs>::operator()(T&& t){
t.format(parse_ctx, fmt_ctx);
}
template<class FmtCtx, class ParseCtx, class Specs>
template<class T>
constexpr void arg_formatter<FmtCtx,ParseCtx,Specs>::operator()(T&& t){
using handler_t = format_specs_checker<dynamic_format_specs_handler<ParseCtx>>;
using specs_t = dynamic_format_specs<typename FmtCtx::char_type>;
specs_t specs;
parse_ctx.advance_to(parse::perform_standard_parse(
parse_ctx.begin(),
parse_ctx.end(),
handler_t{
dynamic_format_specs_handler<ParseCtx>{
parse_ctx,
specs
},
map_to_storage_enum_v<T,typename FmtCtx::char_type>
}
));
normalize_dynamic_format_specs(fmt_ctx, specs);
fmt_ctx.advance_to(perform_standard_format<typename FmtCtx::char_type>(t, fmt_ctx.out(), specs, fmt_ctx.locale()));
}
template<class FmtCtx, class ParseCtx>
template<Handle<FmtCtx> T>
constexpr void empty_formatter<FmtCtx,ParseCtx>::operator()(T&& t){
t.format(parse_ctx, fmt_ctx);
}
template<class FmtCtx, class ParseCtx>
template<class T>
constexpr void empty_formatter<FmtCtx,ParseCtx>::operator()(T&& t){
perform_standard_format<typename FmtCtx::char_type>(t, fmt_ctx.out());
}
} //namespace format
}
#endif

View File

@ -1,83 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_INTERNAL_TYPES_HPP
#define REXY_DETAIL_FORMAT_INTERNAL_TYPES_HPP
#include "../../cx/string.hpp"
#include "standard_types.hpp"
#include <iterator> //back_insert_iterator
#include <type_traits> //type_identity
namespace rexy::fmt::detail{
//forward declare implementation types
template<class Char, class... Args>
class basic_format_string;
template<class Context, class... Args>
class basic_format_arg_store;
template<class Char>
class format_output_buffer_base;
template<class Char, class OutIt>
class basic_format_output_buffer;
struct format_specs;
template<class Char>
struct dynamic_format_specs;
template<class ParseCtx, class... Args>
struct checker_format_specs_handler;
template<class ParseCtx, class FmtCtx>
struct format_specs_handler;
template<class ParseCtx>
struct dynamic_format_specs_handler;
template<class T, class Char>
struct runtime_arg;
template<class T, rexy::cx::string Name>
struct static_arg;
//aliases for easier access to both implementation and standard defined types
template<class Char>
using fmt_buffer_t = format_output_buffer_base<Char>;
template<class Char>
using output_iterator_t = std::back_insert_iterator<fmt_buffer_t<Char>>;
template<class Char>
using fmt_context_t = basic_format_context<output_iterator_t<Char>,Char>;
template<class Char>
using parse_context_t = basic_format_parse_context<Char>;
template<class... Args>
using format_arg_store = basic_format_arg_store<fmt_context_t<char>, Args...>;
template<class... Args>
using wformat_arg_store = basic_format_arg_store<fmt_context_t<wchar_t>, Args...>;
template<class... Args>
using format_string = basic_format_string<char,std::type_identity_t<Args>...>;
template<class... Args>
using wformat_string = basic_format_string<wchar_t, std::type_identity_t<Args>...>;
template<class OutIt>
using format_output_buffer = basic_format_output_buffer<char,OutIt>;
template<class OutIt>
using wformat_output_buffer = basic_format_output_buffer<wchar_t,OutIt>;
template<class Char>
using impl_format_args = basic_format_args<fmt_context_t<Char>>;
template<class Char>
using format_arg = basic_format_arg<fmt_context_t<Char>>;
}
#endif

View File

@ -1,117 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_NAMED_ARGS_HPP
#define REXY_DETAIL_FORMAT_NAMED_ARGS_HPP
#include <type_traits> //remove_cvref, declval, integral_constant
#include <utility> //forward
#include <cstddef> //size_t
#include "../../string_view.hpp"
namespace rexy::fmt{
namespace detail{
template<class T, class Char>
struct arg_base{
const T& value;
const basic_string_view<Char> name;
};
//class used to store name and value for runtime analysis of named arguments
//the type T is the actual formatted type and name is used only for lookup
//during runtime formatting
template<class T, class Char>
struct runtime_arg : public arg_base<T,Char>{
using char_type = Char;
using value_type = std::remove_cvref_t<T>;
};
//class used to store name and value for compile time analysis of named arguments
//the type T is the actual formatted type and Name is used for name lookup in
//format string checking
template<class T, rexy::cx::string Name>
struct static_arg : public arg_base<T,typename decltype(Name)::value_type>{
using char_type = typename decltype(Name)::value_type;
using value_type = std::remove_cvref_t<T>;
static constexpr auto static_name = Name;
constexpr static_arg(const T& v):
arg_base<T,char_type>{v, {Name.c_str(), Name.length()}}{}
static_arg(const static_arg&) = delete;
constexpr static_arg(static_arg&&) = default;
};
//temporary object to store Name to pass off to a compile time argument during assignment
template<rexy::cx::string Name>
struct arg_literal_result{
template<class T>
constexpr auto operator=(T&& t){
return static_arg<std::remove_cvref_t<T>, Name>{std::forward<T>(t)};
}
};
template<class T>
struct is_runtime_named_arg{
template<class U, class Char>
static auto check(runtime_arg<U,Char>) -> std::true_type;
static auto check(...) -> std::false_type;
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>>()))::value;
};
template<class T>
static constexpr bool is_runtime_named_arg_v = is_runtime_named_arg<T>::value;
template<class T>
struct is_static_named_arg{
template<class U, rexy::cx::string Name>
static auto check(static_arg<U,Name>) -> std::true_type;
static auto check(...) -> std::false_type;
static constexpr bool value = decltype(check(std::declval<std::remove_cvref_t<T>>()))::value;
};
template<class T>
static constexpr bool is_static_named_arg_v = is_static_named_arg<T>::value;
template<class T>
concept RuntimeNamedArg = is_runtime_named_arg_v<T>;
template<class T>
concept StaticNamedArg = is_static_named_arg_v<T>;
template<class T>
concept NamedArg = StaticNamedArg<T> || RuntimeNamedArg<T>;
template<class It, std::size_t I, class Arg, class... Args>
constexpr std::size_t find_static_named_arg_id_impl(It first, It last);
template<class It, class... Args>
constexpr std::size_t find_static_named_arg_id(It first, It last);
template<class... Args>
struct count_named_args{
static constexpr std::size_t value = (std::size_t{NamedArg<Args>} + ...);
};
template<class... Args>
static constexpr std::size_t count_named_args_v = count_named_args<Args...>::value;
}
}
#endif

View File

@ -1,57 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_NAMED_ARGS_TPP
#define REXY_DETAIL_FORMAT_NAMED_ARGS_TPP
#include "named_args.hpp"
#include "basic_types.hpp"
#include "../../utility.hpp" //strcmp
namespace rexy::fmt::detail{
template<class It, std::size_t I, class Arg, class... Args>
constexpr std::size_t find_static_named_arg_id_impl(It first, It last){
if constexpr(StaticNamedArg<Arg>){
const auto len = last - first;
const auto arg_len = Arg::static_name.length();
if(len == arg_len){
if(!rexy::strncmp(first, Arg::static_name.c_str(), arg_len)){
return I;
}
}
}
if constexpr(sizeof...(Args) > 0){
return find_static_named_arg_id_impl<It,I+1,Args...>(first, last);
}else{
return invalid_arg_index;
}
}
template<class It, class... Args>
constexpr std::size_t find_static_named_arg_id(It first, It last){
if constexpr(sizeof...(Args) == 0){
return invalid_arg_index;
}else{
return find_static_named_arg_id_impl<It, 0, Args...>(first, last);
}
}
}
#endif

View File

@ -1,123 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_OUTPUT_BUFFER_HPP
#define REXY_DETAIL_FORMAT_OUTPUT_BUFFER_HPP
#include <cstddef> //size_t
#include <cstdio> //fputc, FILE
#include <cwchar> //fputwc
#include "format_error.hpp"
namespace rexy::fmt::detail{
//polymorphic buffer of which a reference can be passed around to prevent
//passing around multiple output iterator types
template<class Char>
class format_output_buffer_base
{
public:
using value_type = Char;
protected:
static constexpr std::size_t s_bufsize = 256;
protected:
Char m_data[s_bufsize];
std::size_t m_size = 0;
std::size_t m_written_count = 0;
public:
format_output_buffer_base(void) = default;
virtual ~format_output_buffer_base(void) = default;
virtual std::size_t write_out(void) = 0;
void clear(void);
void push_back(Char c);
constexpr std::size_t count(void)const;
};
//Used with the 'formatter' to output a type
//OutIt is an iterator where the output is written at the end.
template<class Char, class OutIt>
class basic_format_output_buffer : public format_output_buffer_base<Char>
{
private:
using base = format_output_buffer_base<Char>;
private:
OutIt m_out;
public:
basic_format_output_buffer(OutIt out);
~basic_format_output_buffer(void)override;
std::size_t write_out(void)override;
constexpr OutIt out(void);
private:
std::size_t write_out_simple(void);
};
template<class Char, class OutIt>
class basic_format_output_n_buffer : public format_output_buffer_base<Char>
{
private:
using base = format_output_buffer_base<Char>;
private:
OutIt m_out;
std::size_t m_max_write = 0;
public:
basic_format_output_n_buffer(OutIt out, std::size_t max);
~basic_format_output_n_buffer(void)override;
std::size_t write_out(void)override;
constexpr OutIt out(void);
};
template<class Char>
class basic_format_size_buffer : public format_output_buffer_base<Char>
{
public:
constexpr basic_format_size_buffer(void) = default;
constexpr ~basic_format_size_buffer(void)override;
std::size_t write_out(void)override;
};
template<class Char>
struct print_format_buffer : public format_output_buffer_base<Char>
{
private:
FILE* m_stream;
public:
constexpr print_format_buffer(FILE* stream):
m_stream(stream){}
constexpr ~print_format_buffer(void){
write_out();
}
std::size_t write_out(void)override{
const auto written = fwrite(this->m_data, sizeof(this->m_data[0]), this->m_size, m_stream);
if(written != this->m_size){
REXY_THROW_FORMAT_ERROR("Failed to print data");
}
return written;
}
};
}
#endif

View File

@ -1,153 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_OUTPUT_BUFFER_TPP
#define REXY_DETAIL_FORMAT_OUTPUT_BUFFER_TPP
#include "output_buffer.hpp"
#include <cstddef> //size_t
#include <utility> //move
#include <type_traits> //is_pointer, remove_cvref, integral_constant
#include <algorithm> //min
namespace rexy::fmt::detail{
///////////////////////format_output_buffer_base////////////////////////
template<class Char>
void format_output_buffer_base<Char>::clear(void){
m_size = 0;
}
template<class Char>
void format_output_buffer_base<Char>::push_back(Char c){
if(m_size == s_bufsize){
m_written_count += write_out();
clear();
}
m_data[m_size++] = c;
}
template<class Char>
constexpr std::size_t format_output_buffer_base<Char>::count(void)const{
//include data that will be written during next call to write_out
return m_written_count + m_size;
}
///////////////////////basic_format_output_buffer////////////////////////
template<class Char, class OutIt>
basic_format_output_buffer<Char,OutIt>::basic_format_output_buffer(OutIt out):
m_out(out){}
template<class Char, class OutIt>
basic_format_output_buffer<Char,OutIt>::~basic_format_output_buffer(void){
write_out();
}
template<class T>
concept HasContainerAlias = requires{
typename T::container_type;
};
template<class T, class It>
concept HasInsertMethod = requires(T t, It i){
{t.insert(1, i, i)}; //don't use 0 index because pointer conversion causes ambiguous call
{t.size()};
};
template<class It>
struct something : public It{
template<class U = something, class C = decltype(U::container)>
static std::true_type check(int);
static std::false_type check(...);
static constexpr bool value = decltype(check(0))::value;
};
template<class Char, class OutIt>
OutIt real_write_out(const Char* start, std::size_t write_count, OutIt out){
static constexpr bool has_container = something<OutIt>::value;//decltype(container_traits<OutIt>::check(0))::value;
//optimize for types where direct access to the underlying container is available
//check for a container member and a 'container_type' typedef in OutIt
//reason for the type check is that without 'container_type' it might not be safe to access the 'container'
if constexpr(has_container && HasContainerAlias<OutIt>){
struct container_access : public OutIt{
using OutIt::container;
};
container_access ca{out};
auto& container = ca.container;
if constexpr(HasInsertMethod<typename OutIt::container_type,const Char*>){
if constexpr(std::is_pointer_v<std::remove_cvref_t<decltype(container)>>){
container->insert(container->size(), start, start + write_count);
}else{
container.insert(container.size(), start, start + write_count);
}
return std::move(out);
}
}
for(std::size_t i = 0;i < write_count;++i){
out = start[i];
}
return std::move(out);
}
template<class Char, class OutIt>
std::size_t basic_format_output_buffer<Char,OutIt>::write_out(void){
m_out = real_write_out(this->m_data, this->m_size, std::move(m_out));
return this->m_size;
}
template<class Char, class OutIt>
constexpr OutIt basic_format_output_buffer<Char,OutIt>::out(void){
return std::move(m_out);
}
///////////////////////basic_format_output_n_buffer////////////////////////
template<class Char, class OutIt>
basic_format_output_n_buffer<Char,OutIt>::basic_format_output_n_buffer(OutIt out, std::size_t max):
m_out(out),
m_max_write(max){}
template<class Char, class OutIt>
basic_format_output_n_buffer<Char,OutIt>::~basic_format_output_n_buffer(void){
write_out();
}
template<class Char, class OutIt>
std::size_t basic_format_output_n_buffer<Char,OutIt>::write_out(void){
const auto to_write = std::min(this->size, m_max_write);
m_out = real_write_out(this->m_data, to_write, std::move(m_out));
m_max_write -= to_write;
return to_write;
}
template<class Char, class OutIt>
constexpr OutIt basic_format_output_n_buffer<Char,OutIt>::out(void){
return std::move(m_out);
}
/////////////////////////basic_format_size_buffer//////////////////////////
template<class Char>
constexpr basic_format_size_buffer<Char>::~basic_format_size_buffer(void){
write_out();
}
template<class Char>
std::size_t basic_format_size_buffer<Char>::write_out(void){
return this->m_size;
}
}
#endif

View File

@ -1,116 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_PARSE_HPP
#define REXY_DETAIL_FORMAT_PARSE_HPP
#include "../../string_view.hpp"
#include <cstddef> //size_t
namespace rexy::fmt::detail::parse{
//A few basic string checking functions
template<class Char>
constexpr auto find_first_of_it(Char v,
typename basic_string_view<Char>::const_iterator start_it,
typename basic_string_view<Char>::const_iterator last_it);
template<class Char>
constexpr auto find_first_of_it(const basic_string_view<Char>& str, Char v);
template<class It>
constexpr bool check_duplicate_char(It start, It end);
template<class Char>
constexpr bool is_a_number(Char c);
template<class It>
constexpr int to_integer(It start, It end);
template<class It>
constexpr It find_valid_index(It start, It end);
//Used with 'visit_format_arg' as the 'fun' arg. Gets the value of the argument as a 'long long'
//if the argument is of integral type. Throws an error otherwise
struct dynamic_integer_retriever{
template<class T>
constexpr long long operator()(T&& t);
};
//Used during call to 'perform_standard_nested_replacement_field' as the 'Adapter' type.
//Calls 'on_dynamic_width' of 'specs'
template<class Specs>
struct dynamic_width_adapter{
Specs& specs;
constexpr decltype(auto) operator()(void);
constexpr decltype(auto) operator()(int i);
template<class It>
constexpr decltype(auto) operator()(It start, It last);
};
//Used during call to 'perform_standard_nested_replacement_field' as the 'Adapter' type.
//Calls 'on_dynamic_precision' of 'specs'
template<class Specs>
struct dynamic_precision_adapter{
Specs& specs;
constexpr decltype(auto) operator()(void);
constexpr decltype(auto) operator()(int i);
template<class It>
constexpr decltype(auto) operator()(It start, It last);
};
template<class Handler>
struct dynamic_index_adapter{
Handler& handler;
std::size_t& id;
constexpr decltype(auto) operator()(void);
constexpr decltype(auto) operator()(int i);
template<class It>
constexpr decltype(auto) operator()(It start, It last);
};
//Standalone functions for parsing standard format fields
template<class It, class FormatSpecs>
constexpr It perform_standard_fill_align_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_sign_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_alt_form_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_zero_fill_option(It start, It last, FormatSpecs&& specs);
template<class It, class Adapter>
constexpr It perform_standard_nested_replacement_field(It start, It last, Adapter&& func);
template<class It, class FormatSpecs>
constexpr It perform_standard_width_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_precision_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_locale_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_type_option(It start, It last, FormatSpecs&& specs);
template<class It, class FormatSpecs>
constexpr It perform_standard_parse(It start, It last, FormatSpecs&& specs);
//Standalone functions for parsing the entire format string
template<class Handler, class It>
constexpr It perform_format_index_spec(Handler&& handler, It start, It last, std::size_t& id);
template<class Handler, class It>
constexpr It perform_empty_format_field_parse(Handler&& handler, It start, It last);
template<class Handler, class It>
constexpr It perform_format_field_parse(Handler&& handler, It start, It last);
template<class Handler, class Char>
constexpr void perform_parse(Handler&& handler, basic_string_view<Char> fmt);
}
#endif

View File

@ -1,354 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_PARSE_TPP
#define REXY_DETAIL_FORMAT_PARSE_TPP
#include "parse.hpp"
#include "format_error.hpp"
#include "../../string_view.hpp"
#include <cstddef> //size_t
#include <type_traits> //is_integral, remove_cvref, add_lvalue_reference, remove_reference
#include <algorithm> //min
namespace rexy::fmt::detail::parse{
template<class Char>
constexpr auto find_first_of_it(Char v,
typename basic_string_view<Char>::const_iterator start_it,
typename basic_string_view<Char>::const_iterator last_it)
{
const basic_string_view<Char> view{start_it, last_it};
const std::size_t range_size = last_it - start_it;
return start_it + std::min(view.find_first_of(v), range_size);
}
template<class Char>
constexpr auto find_first_of_it(const basic_string_view<Char>& str, Char v){
return find_first_of_it(v, str.begin(), str.end());
}
template<class It>
constexpr bool check_duplicate_char(It start, It end){
if(start == end){
return false;
}
const auto next = start + 1;
return *start == *next;
}
template<class Char>
constexpr bool is_a_number(Char c){
return (c >= '0' && c <= '9');
}
template<class Char>
constexpr bool is_valid_name_char(Char c){
return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') ||
(c == '_');
}
template<class It>
constexpr int to_integer(It start, It end){
int retval = 0;
std::size_t mul = 1;
for(auto it = end;it != start;--it){
const auto cur = it-1;
retval += ((*cur - '0') * mul);
mul *= 10;
}
return retval;
}
template<class T>
constexpr long long dynamic_integer_retriever::operator()(T&& t){
if constexpr(std::is_integral_v<std::remove_cvref_t<T>>){
return static_cast<long long>(t);
}else{
REXY_THROW_FORMAT_ERROR("Invalid dynamic specifier");
}
return {};
}
template<class Specs>
constexpr decltype(auto) dynamic_width_adapter<Specs>::operator()(void){
return specs.on_dynamic_width();
}
template<class Specs>
constexpr decltype(auto) dynamic_width_adapter<Specs>::operator()(int i){
return specs.on_dynamic_width(i);
}
template<class Specs>
template<class It>
constexpr decltype(auto) dynamic_width_adapter<Specs>::operator()(It start, It last){
return specs.on_dynamic_width(start, last);
}
template<class Specs>
constexpr decltype(auto) dynamic_precision_adapter<Specs>::operator()(void){
return specs.on_dynamic_precision();
}
template<class Specs>
constexpr decltype(auto) dynamic_precision_adapter<Specs>::operator()(int i){
return specs.on_dynamic_precision(i);
}
template<class Specs>
template<class It>
constexpr decltype(auto) dynamic_precision_adapter<Specs>::operator()(It start, It last){
return specs.on_dynamic_precision(start, last);
}
template<class Handler>
constexpr decltype(auto) dynamic_index_adapter<Handler>::operator()(void){
return (id = handler.on_arg_id());
}
template<class Handler>
constexpr decltype(auto) dynamic_index_adapter<Handler>::operator()(int i){
id = i;
return handler.on_arg_id(i);
}
template<class Handler>
template<class It>
constexpr decltype(auto) dynamic_index_adapter<Handler>::operator()(It start, It last){
id = handler.on_arg_id(start, last);
return id;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_fill_align_option(It start, It last, FormatSpecs&& specs){
char fill_val = ' ';
It it = start;
for(int i = 0;i < 2 && it != last;++i){
if(*it == '>' || *it == '<' || *it == '^'){
specs.on_align(*it, fill_val);
return ++it;
}
fill_val = *it;
++it;
}
return start;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_sign_option(It start, It last, FormatSpecs&& specs){
if(*start == '+' || *start == '-' || *start == ' '){
specs.on_sign(*start);
return ++start;
}
return start;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_alt_form_option(It start, It last, FormatSpecs&& specs){
if(*start == '#'){
specs.on_alt_form();
++start;
}
return start;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_zero_fill_option(It start, It last, FormatSpecs&& specs){
if(*start == '0'){
specs.on_zero_fill();
++start;
}
return start;
}
template<class It, class Adapter>
constexpr It perform_index_retrieve(It start, It last, Adapter&& func){
if(*start == '0'){
func(0);
return start+1;
}
if(*start == '}' || *start == ':'){
func();
return start;
}
if(!is_a_number(*start)){
auto it = start;
for(;it != last;++it){
if(!is_valid_name_char(*it)){
func(start, it);
return it;
}
}
return last;
}
for(auto it = start+1;it != last;++it){
if(!is_a_number(*it)){
func(to_integer(start, it));
return it;
}
}
return last;
}
template<class It, class Adapter>
constexpr It perform_standard_nested_replacement_field(It start, It last, Adapter&& func){
auto it = perform_index_retrieve(start, last, func);
if(*it != '}'){
REXY_THROW_FORMAT_ERROR("Dynamic index invalid spec");
}
return it+1;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_width_option(It start, It last, FormatSpecs&& specs){
using specs_t = std::add_lvalue_reference_t<std::remove_reference_t<FormatSpecs>>;
if(*start == '{'){
return perform_standard_nested_replacement_field(start+1, last, dynamic_width_adapter<specs_t>{specs});
}
if(*start == '0'){
REXY_THROW_FORMAT_ERROR("Field invalid spec");
}
It it = start;
for(;is_a_number(*it) && it != last;++it){}
if(it == start){
return start;
}
specs.on_width(to_integer(start, it));
return it;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_precision_option(It start, It last, FormatSpecs&& specs){
using specs_t = std::add_lvalue_reference_t<std::remove_reference_t<FormatSpecs>>;
if(*start != '.'){
return start;
}
++start;
if(*start == '{'){
return perform_standard_nested_replacement_field(start+1, last, dynamic_precision_adapter<specs_t>{specs});
}
if(*start == '0'){
REXY_THROW_FORMAT_ERROR("Field invalid spec");
}
It it = start;
for(;is_a_number(*it) && it != last;++it){}
if(it == start){
REXY_THROW_FORMAT_ERROR("Field invalid spec");
}
specs.on_precision(to_integer(start, it));
return it;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_locale_option(It start, It last, FormatSpecs&& specs){
if(*start == 'L'){
specs.on_locale();
return ++start;
}
return start;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_type_option(It start, It last, FormatSpecs&& specs){
if(*start == '}'){
specs.on_type_option();
return start;
}
specs.on_type_option(*start);
return ++start;
}
template<class It, class FormatSpecs>
constexpr It perform_standard_parse(It start, It last, FormatSpecs&& specs){
using specs_t = std::add_lvalue_reference_t<std::remove_reference_t<FormatSpecs>>;
using std_fmt_fn = It(*)(It,It,specs_t);
constexpr std_fmt_fn fns[] = {
perform_standard_fill_align_option<It,specs_t>,
perform_standard_sign_option<It,specs_t>,
perform_standard_alt_form_option<It,specs_t>,
perform_standard_zero_fill_option<It,specs_t>,
perform_standard_width_option<It,specs_t>,
perform_standard_precision_option<It,specs_t>,
perform_standard_locale_option<It,specs_t>,
perform_standard_type_option<It,specs_t>
};
constexpr int num_std_fns = sizeof(fns) / sizeof(fns[0]);
for(int i = 0;i < num_std_fns;++i){
start = fns[i](start, last, specs);
if(start == last){
break;
}
}
if(*start != '}'){
REXY_THROW_FORMAT_ERROR("Missing closing brace for format field");
}
return start;
}
template<class Handler, class It>
constexpr It perform_format_index_spec(Handler&& handler, It start, It last, std::size_t& id){
dynamic_index_adapter<Handler> adapter{handler, id};
const auto it = perform_index_retrieve(start, last, adapter);
if(*it != '}' && *it != ':'){
REXY_THROW_FORMAT_ERROR("Invalid index spec");
}
return it;
}
template<class Handler, class It>
constexpr It perform_format_field_parse(Handler&& handler, It start, It last){
if(start == last){
REXY_THROW_FORMAT_ERROR("Unmatched brace");
}
std::size_t index = 0;
start = perform_format_index_spec(handler, start, last, index);
if(*start == ':'){
return handler.do_format_spec(start+1, last, index);
}
handler.do_empty_format(start, last, index);
return start;
}
template<class Handler, class Char>
constexpr void perform_parse(Handler&& handler, basic_string_view<Char> fmt){
using char_type = Char;
auto work_it = fmt.begin();
auto open_brace_it = fmt.begin();
auto close_brace_it = fmt.begin();
while(true){
open_brace_it = find_first_of_it(char_type{'{'}, work_it, fmt.end());
while(true){
close_brace_it = find_first_of_it(char_type{'}'}, work_it, open_brace_it);
if(close_brace_it == open_brace_it){
//don't go past open brace because we still need to parse it
handler.do_raw(work_it, close_brace_it);
work_it = close_brace_it;
break;
}
if(check_duplicate_char(close_brace_it, fmt.end())){
++close_brace_it;
handler.do_raw(work_it, close_brace_it);
//go past closing brace to not double parse it
work_it = close_brace_it + 1;
}else{
REXY_THROW_FORMAT_ERROR("Unmatched brace");
}
}
if(open_brace_it == fmt.end()){
break;
}
if(check_duplicate_char(open_brace_it, fmt.end())){
++open_brace_it;
handler.do_raw(work_it, open_brace_it);
work_it = open_brace_it + 1;
continue;
}
work_it = perform_format_field_parse(handler, open_brace_it+1, fmt.end()) + 1;
}
return;
}
}
#endif

View File

@ -1,61 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_PARSE_CONTEXT_HPP
#define REXY_DETAIL_FORMAT_PARSE_CONTEXT_HPP
#include <cstddef> //size_t
#include "../../string_view.hpp"
namespace rexy::fmt{
//Holds the format string for use in calls to 'formatter<T>::parse'
//Additionally keeps tally of the current argument index for automatic replacement indexing or
//switches to manual indexing mode when encountering a manually indexed field. Throws error on mode switch.
template<class Char>
class basic_format_parse_context
{
public:
using char_type = Char;
using iterator = typename basic_string_view<Char>::const_iterator;
using const_iterator = typename basic_string_view<Char>::const_iterator;
public:
basic_string_view<char_type> format;
std::size_t arg_count;
long long arg_index = 0;
public:
//fmt is the format specifier, num_args is 'sizeof...(Args)' where 'Args' is the parameter pack of the format call
constexpr explicit basic_format_parse_context(basic_string_view<char_type> fmt, std::size_t num_args = 0)noexcept;
basic_format_parse_context(const basic_format_parse_context&) = delete;
basic_format_parse_context(basic_format_parse_context&&) = delete;
basic_format_parse_context& operator=(basic_format_parse_context&&) = delete;
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
constexpr const_iterator begin(void)const noexcept;
constexpr const_iterator end(void)const noexcept;
constexpr void advance_to(const_iterator it);
constexpr std::size_t next_arg_id(void);
constexpr void check_arg_id(std::size_t id);
};
}
#endif

View File

@ -1,80 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_PARSE_CONTEXT_TPP
#define REXY_DETAIL_FORMAT_PARSE_CONTEXT_TPP
#include "../../compat/if_consteval.hpp"
#include "parse_context.hpp"
#include "format_error.hpp"
#include <cstddef> //size_t
namespace rexy::fmt{
/////////////////////////////basic_format_parse_context//////////////////////////////
template<class Char>
constexpr basic_format_parse_context<Char>::basic_format_parse_context(basic_string_view<char_type> fmt, std::size_t num_args)noexcept:
format(fmt),
arg_count(num_args){}
template<class Char>
constexpr auto basic_format_parse_context<Char>::begin(void)const noexcept -> const_iterator{
return format.begin();
}
template<class Char>
constexpr auto basic_format_parse_context<Char>::end(void)const noexcept -> const_iterator{
return format.end();
}
template<class Char>
constexpr void basic_format_parse_context<Char>::advance_to(const_iterator it){
const std::size_t diff = it - format.begin();
format.remove_prefix(diff);
}
template<class Char>
constexpr std::size_t basic_format_parse_context<Char>::next_arg_id(void){
if(arg_index < 0){
//error, already in manual mode
REXY_THROW_FORMAT_ERROR("Invalid indexing mode switch");
}
REXY_if_consteval{
if(arg_index >= arg_count){
REXY_THROW_FORMAT_ERROR("Missing argument");
}
}
return arg_index++;
}
template<class Char>
constexpr void basic_format_parse_context<Char>::check_arg_id(std::size_t id){
if(arg_index > 0){
//error, already in automatic mode
REXY_THROW_FORMAT_ERROR("Invalid indexing mode switch");
}
REXY_if_consteval{
if(id >= arg_count){
REXY_THROW_FORMAT_ERROR("Missing argument");
}
}
arg_index = detail::invalid_arg_index;
}
}
#endif

View File

@ -1,129 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_SPECS_HANDLER_HPP
#define REXY_DETAIL_FORMAT_SPECS_HANDLER_HPP
#include "../../compat/if_consteval.hpp"
namespace rexy::fmt::detail{
//Stores standard format-spec information to use later in formatting
template<class ParseCtx, class FmtCtx>
struct format_specs_handler{
ParseCtx& parse_ctx;
FmtCtx& fmt_ctx;
format_specs& specs;
constexpr format_specs_handler(ParseCtx& pc, FmtCtx& fc, format_specs& s):
parse_ctx(pc),
fmt_ctx(fc),
specs(s){}
constexpr void on_width(int w);
constexpr void on_dynamic_width(void);
constexpr void on_dynamic_width(int index);
template<class It>
constexpr void on_dynamic_width(It first, It last);
constexpr void on_precision(int p);
constexpr void on_dynamic_precision(void);
constexpr void on_dynamic_precision(int index);
template<class It>
constexpr void on_dynamic_precision(It first, It last);
constexpr void on_locale(void);
constexpr void on_type_option(int o = 0);
constexpr void on_align(int al, int val);
constexpr void on_sign(int s);
constexpr void on_alt_form(void);
constexpr void on_zero_fill(void);
};
//Stores standard format-spec information to use later in formatting. Stores indices of dynamic specifiers
//to be retrieved later.
template<class ParseCtx>
struct dynamic_format_specs_handler{
using specs_type = dynamic_format_specs<typename ParseCtx::char_type>;
ParseCtx& parse_ctx;
specs_type& specs;
constexpr dynamic_format_specs_handler(ParseCtx& pc, specs_type& s);
constexpr void on_width(int w);
constexpr void on_dynamic_width(void);
constexpr void on_dynamic_width(int index);
template<class It>
constexpr void on_dynamic_width(It first, It last);
constexpr void on_precision(int p);
constexpr void on_dynamic_precision(void);
constexpr void on_dynamic_precision(int index);
template<class It>
constexpr void on_dynamic_precision(It first, It last);
constexpr void on_locale(void);
constexpr void on_type_option(int o = 0);
constexpr void on_align(int al, int val);
constexpr void on_sign(int s);
constexpr void on_alt_form(void);
constexpr void on_zero_fill(void);
};
//Used during compile time only. Checks dynamic specifiers given types pack as template parameters.
template<class ParseCtx, class... Args>
struct cx_format_specs_handler : public dynamic_format_specs_handler<ParseCtx>{
using char_type = typename ParseCtx::char_type;
constexpr cx_format_specs_handler(ParseCtx& pc, dynamic_format_specs<char_type>& s):
dynamic_format_specs_handler<ParseCtx>(pc, s){
REXY_if_not_consteval{
throw 0;
}
}
constexpr void on_dynamic_width(void);
constexpr void on_dynamic_width(int index);
template<class It>
constexpr void on_dynamic_width(It first, It last);
constexpr void on_dynamic_precision(void);
constexpr void on_dynamic_precision(int index);
template<class It>
constexpr void on_dynamic_precision(It first, It last);
};
template<class Handler>
struct format_specs_checker : public Handler{
storage_type arg_type = storage_type::none_t;
bool requires_arithmetic_presentation = false;
constexpr format_specs_checker(const Handler& h, storage_type type);
constexpr void on_precision(int p);
constexpr void on_dynamic_precision(void);
constexpr void on_dynamic_precision(int index);
template<class It>
constexpr void on_dynamic_precision(It first, It last);
constexpr void on_locale(void);
constexpr void on_sign(int s);
constexpr void on_alt_form(void);
constexpr void on_zero_fill(void);
constexpr void on_type_option(int type = 0);
private:
constexpr void check_precision(void);
constexpr void check_arithmetic_type(void);
};
}
#endif

View File

@ -1,389 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_SPECS_HANDLER_TPP
#define REXY_DETAIL_FORMAT_SPECS_HANDLER_TPP
#include "specs_handler.hpp"
#include "format_error.hpp"
#include "traits.hpp"
#include "named_args.hpp"
#include "format_args.hpp"
#include "internal_types.hpp"
#include "standard_types.hpp"
#include "basic_types.hpp"
namespace rexy::fmt::detail{
/////////////////////////////format_specs_handler//////////////////////////////
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_width(int w){
specs.width = w;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_width(void){
const auto index = parse_ctx.next_arg_id();
const auto arg = fmt_ctx.arg(index);
const auto value = visit_format_arg(parse::dynamic_integer_retriever{}, arg);
on_width(value);
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_width(int index){
parse_ctx.check_arg_id(index);
const auto arg = fmt_ctx.arg(index);
const auto value = visit_format_arg(parse::dynamic_integer_retriever{}, arg);
on_width(value);
}
template<class ParseCtx, class FmtCtx>
template<class It>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_width(It first, It last){
on_dynamic_width(fmt_ctx.arg_index(first, last));
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_precision(int p){
specs.precision = p;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_precision(void){
const auto index = parse_ctx.next_arg_id();
const auto arg = fmt_ctx.arg(index);
const auto value = visit_format_arg(parse::dynamic_integer_retriever{}, arg);
on_precision(value);
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_precision(int index){
parse_ctx.check_arg_id(index);
const auto arg = fmt_ctx.arg(index);
const auto value = visit_format_arg(parse::dynamic_integer_retriever{}, arg);
on_precision(value);
}
template<class ParseCtx, class FmtCtx>
template<class It>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_dynamic_precision(It first, It last){
on_dynamic_precision(fmt_ctx.arg_index(first, last));
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_locale(void){
specs.locale = true;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_type_option(int o){
specs.type = o;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_align(int al, int val){
specs.align = static_cast<alignment>(al);
specs.align_char = val;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_sign(int s){
specs.sign = s;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_alt_form(void){
specs.alt_form = true;
}
template<class ParseCtx, class FmtCtx>
constexpr void format_specs_handler<ParseCtx,FmtCtx>::on_zero_fill(void){
specs.zero_fill = true;
}
/////////////////////////////dynamic_format_specs_handler//////////////////////////////
template<class ParseCtx>
constexpr dynamic_format_specs_handler<ParseCtx>::dynamic_format_specs_handler(ParseCtx& pc, dynamic_format_specs<typename ParseCtx::char_type>& s):
parse_ctx(pc),
specs(s){}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_width(int w){
specs.width = w;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_width(void){
specs.dyn_width.index = parse_ctx.next_arg_id();
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_width(int index){
parse_ctx.check_arg_id(index);
specs.dyn_width.index = index;
}
template<class ParseCtx>
template<class It>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_width(It first, It last){
parse_ctx.check_arg_id(0); //just to make sure we aren't switching indexing modes
specs.dyn_width.name = {first, std::size_t(last - first)};
specs.width_type = dyn_type::string;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_precision(int p){
specs.precision = p;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_precision(void){
specs.dyn_precision.index = parse_ctx.next_arg_id();
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_precision(int index){
parse_ctx.check_arg_id(index);
specs.dyn_precision.index = index;
}
template<class ParseCtx>
template<class It>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_dynamic_precision(It first, It last){
parse_ctx.check_arg_id(0); //just to make sure we aren't switching indexing modes
specs.dyn_precision.name = {first, std::size_t(last - first)};
specs.precision_type = dyn_type::string;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_locale(void){
specs.locale = true;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_type_option(int o){
specs.type = o;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_align(int al, int val){
specs.align = static_cast<alignment>(al);
specs.align_char = val;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_sign(int s){
specs.sign = s;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_alt_form(void){
specs.alt_form = true;
}
template<class ParseCtx>
constexpr void dynamic_format_specs_handler<ParseCtx>::on_zero_fill(void){
specs.zero_fill = true;
}
/////////////////////////////cx_format_specs_handler//////////////////////////////
template<class ParseCtx, class... Args>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_width(void){
const auto index = this->parse_ctx.next_arg_id();
if(!is_dynamic_integer<char_type,Args...>(index)){
REXY_THROW_FORMAT_ERROR("Invalid type given as dynamic width");
}
}
template<class ParseCtx, class... Args>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_width(int index){
this->parse_ctx.check_arg_id(index);
if(!is_dynamic_integer<char_type,Args...>(index)){
REXY_THROW_FORMAT_ERROR("Invalid type given as dynamic width");
}
}
template<class ParseCtx, class... Args>
template<class It>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_width(It first, It last){
on_dynamic_width(find_static_named_arg_id<It,Args...>(first, last));
}
template<class ParseCtx, class... Args>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_precision(void){
const auto index = this->parse_ctx.next_arg_id();
if(!is_dynamic_integer<char_type,Args...>(index)){
REXY_THROW_FORMAT_ERROR("Invalid type given as dynamic precision");
}
}
template<class ParseCtx, class... Args>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_precision(int index){
this->parse_ctx.check_arg_id(index);
if(!is_dynamic_integer<char_type,Args...>(index)){
REXY_THROW_FORMAT_ERROR("Invalid type given as dynamic precision");
}
}
template<class ParseCtx, class... Args>
template<class It>
constexpr void cx_format_specs_handler<ParseCtx,Args...>::on_dynamic_precision(It first, It last){
on_dynamic_precision(find_static_named_arg_id<It,Args...>(first, last));
}
/////////////////////////////format_specs_checker//////////////////////////////
template<class Handler>
constexpr format_specs_checker<Handler>::format_specs_checker(const Handler& h, storage_type type):
Handler(h), arg_type(type){}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_precision(int p){
check_precision();
Handler::on_precision(p);
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_dynamic_precision(void){
check_precision();
Handler::on_dynamic_precision();
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_dynamic_precision(int index){
check_precision();
Handler::on_dynamic_precision(index);
}
template<class Handler>
template<class It>
constexpr void format_specs_checker<Handler>::on_dynamic_precision(It first, It last){
check_precision();
Handler::on_dynamic_precision(first, last);
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_locale(void){
check_arithmetic_type();
Handler::on_locale();
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_sign(int s){
requires_arithmetic_presentation = true;
check_arithmetic_type();
Handler::on_sign(s);
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_alt_form(void){
requires_arithmetic_presentation = true;
check_arithmetic_type();
Handler::on_alt_form();
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_zero_fill(void){
requires_arithmetic_presentation = true;
check_arithmetic_type();
Handler::on_zero_fill();
}
template<class Handler>
constexpr void format_specs_checker<Handler>::on_type_option(int type){
presentation& chosen = this->specs.present;
switch(type){
case 0:
break;
case 'b':
case 'B':
case 'd':
case 'o':
case 'x':
case 'X':
chosen = presentation::int_t;
break;
case 'c':
chosen = presentation::char_t;
break;
case 's':
chosen = presentation::string_t;
break;
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
chosen = presentation::float_t;
break;
case 'p':
chosen = presentation::ptr_t;
break;
default:
REXY_THROW_FORMAT_ERROR("Invalid type specifier");
};
switch(arg_type){
case storage_type::none_t:
REXY_THROW_FORMAT_ERROR("Invalid argument");
break;
case storage_type::bool_t:
if(chosen == presentation::default_t){
chosen = presentation::string_t;
}
if(chosen != presentation::string_t && chosen != presentation::int_t && chosen != presentation::char_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for bool");
}
break;
case storage_type::char_t:
if(chosen == presentation::default_t){
chosen = presentation::char_t;
}
if(chosen != presentation::char_t && chosen != presentation::int_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for character");
}
break;
case storage_type::int_t:
case storage_type::uint_t:
case storage_type::long_long_t:
case storage_type::ulong_long_t:
if(chosen == presentation::default_t){
chosen = presentation::int_t;
}
if(chosen != presentation::int_t && chosen != presentation::char_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for integral");
}
break;
case storage_type::float_t:
case storage_type::double_t:
case storage_type::long_double_t:
if(chosen == presentation::default_t){
chosen = presentation::float_t;
}
if(chosen != presentation::float_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for floating point");
}
break;
case storage_type::char_ptr_t:
case storage_type::string_t:
if(chosen == presentation::default_t){
chosen = presentation::string_t;
}
if(chosen != presentation::string_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for string");
}
break;
case storage_type::ptr_t:
if(chosen == presentation::default_t){
chosen = presentation::ptr_t;
}
if(chosen != presentation::ptr_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier for pointer");
}
break;
case storage_type::custom_t:
break;
};
if(requires_arithmetic_presentation && chosen != presentation::int_t && chosen != presentation::float_t){
REXY_THROW_FORMAT_ERROR("Invalid type specifier with modifier requiring integer presentation");
}
return Handler::on_type_option(type);
}
template<class Handler>
constexpr void format_specs_checker<Handler>::check_precision(void){
if(!(is_floating_storage_type(arg_type) || is_string_storage_type(arg_type))){
REXY_THROW_FORMAT_ERROR("Precision not valid for argument type");
}
}
template<class Handler>
constexpr void format_specs_checker<Handler>::check_arithmetic_type(void){
if(!is_integral_storage_type(arg_type)){
REXY_THROW_FORMAT_ERROR("Formatting argument requires an arithmetic type");
}
}
}
#endif

View File

@ -1,38 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_STANDARD_TYPES_HPP
#define REXY_DETAIL_FORMAT_STANDARD_TYPES_HPP
namespace rexy::fmt{
template<class T, class Char>
class formatter;
template<class Context>
class basic_format_arg;
template<class Context>
class basic_format_args;
template<class OutIt, class Char>
class basic_format_context;
template<class Char>
class basic_format_parse_context;
struct format_error;
}
#endif

View File

@ -1,71 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_STORAGE_HPP
#define REXY_DETAIL_FORMAT_STORAGE_HPP
#include <type_traits> //declval
namespace rexy::fmt::detail{
//tag for use in basic_format_arg(s)
enum class storage_type{
none_t = 0,
bool_t,
char_t,
int_t,
uint_t,
long_long_t,
ulong_long_t,
float_t,
double_t,
long_double_t,
char_ptr_t,
string_t,
ptr_t,
custom_t
};
constexpr bool is_integral_storage_type(storage_type t){
return t >= storage_type::bool_t && t <= storage_type::long_double_t;
}
constexpr bool is_integer_storage_type(storage_type t){
return t >= storage_type::bool_t && t <= storage_type::ulong_long_t;
}
constexpr bool is_floating_storage_type(storage_type t){
return t >= storage_type::float_t && t <= storage_type::long_double_t;
}
constexpr bool is_string_storage_type(storage_type t){
return t == storage_type::string_t || t == storage_type::char_ptr_t;
}
//Mappings from actual type to the type used in basic_format_arg(s)
template<class T, class Char>
consteval storage_type map_to_storage_enum(void);
template<class T, class Char>
static constexpr storage_type map_to_storage_enum_v = map_to_storage_enum<T,Char>();
template<class Context>
struct map_to_stored_type_helper;
template<class T, class Context>
using stored_type_t = decltype(std::declval<map_to_stored_type_helper<Context>>()(std::declval<T>()));
}
#endif

View File

@ -1,114 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_STORAGE_TPP
#define REXY_DETAIL_FORMAT_STORAGE_TPP
#include "storage.hpp"
#include "named_args.hpp"
#include <type_traits> //is_pointer, remove_cvref, remove_pointer, is_same, is_arithmetic
#include <concepts> //unsigned_integral, signed_integral, floating_point
#include <cstddef> //nullptr_t
namespace rexy::fmt::detail{
///////////////////////storage type mapping////////////////////////
template<class T, class Char>
consteval storage_type map_to_storage_enum(void){
using type = std::remove_cvref_t<T>;
if constexpr(std::is_pointer_v<type>){
if constexpr(std::is_same_v<std::remove_cv_t<std::remove_pointer_t<type>>,Char>){
return storage_type::char_ptr_t;
}else{
return storage_type::ptr_t;
}
}else if constexpr(std::is_same_v<type,basic_string_view<Char>>){
return storage_type::string_t;
}else if constexpr(std::is_same_v<type,Char>){
return storage_type::char_t;
}else if constexpr(std::is_same_v<type,std::monostate>){
return storage_type::none_t;
}else if constexpr(std::is_same_v<type,bool>){
return storage_type::bool_t;
}else if constexpr(std::is_same_v<type,int>){
return storage_type::int_t;
}else if constexpr(std::is_same_v<type,unsigned int>){
return storage_type::uint_t;
}else if constexpr(std::is_same_v<type,long long>){
return storage_type::long_long_t;
}else if constexpr(std::is_same_v<type,unsigned long long>){
return storage_type::ulong_long_t;
}else if constexpr(std::is_same_v<type,float>){
return storage_type::float_t;
}else if constexpr(std::is_same_v<type,double>){
return storage_type::double_t;
}else if constexpr(std::is_same_v<type,long double>){
return storage_type::long_double_t;
}else{
return storage_type::custom_t;
}
}
template<class Context>
struct map_to_stored_type_helper{
using char_type = typename Context::char_type;
template<class T>
requires (!std::is_arithmetic_v<T> && !std::is_pointer_v<T> && !NamedArg<T>)
constexpr auto operator()(T) -> typename basic_format_arg<Context>::handle;
constexpr auto operator()(std::unsigned_integral auto i){
if constexpr(sizeof(i) <= sizeof(unsigned int)){
using uint = unsigned int;
return uint{};
}else{
using ull = unsigned long long;
return ull{};
}
}
constexpr auto operator()(std::signed_integral auto i){
if constexpr(sizeof(i) <= sizeof(int)){
return int{};
}else{
using ll = long long;
return ll{};
}
}
template<std::floating_point T>
constexpr auto operator()(T) -> std::remove_cvref_t<T>;
constexpr auto operator()(char_type) -> char_type;
constexpr auto operator()(bool) -> bool;
constexpr auto operator()(float) -> float;
constexpr auto operator()(double) -> double;
constexpr auto operator()(long double) -> long double;
constexpr auto operator()(const char_type*) -> const char_type*;
constexpr auto operator()(basic_string_view<char_type>) -> basic_string_view<char_type>;
constexpr auto operator()(basic_string<char_type>) -> basic_string_view<char_type>;
template<class T>
requires (!std::is_same_v<std::remove_cvref_t<T>,char_type>)
constexpr auto operator()(T*) -> const void*;
constexpr auto operator()(std::nullptr_t) -> const void*;
template<NamedArg T>
constexpr auto operator()(T t) -> decltype((*this)(t.value));
};
}
#endif

View File

@ -1,150 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_TRAITS_HPP
#define REXY_DETAIL_FORMAT_TRAITS_HPP
#include <type_traits> //is_convertible, is_floating_point, integral_constant, is_same, remove_cvref
#include <concepts> //integral, floating_point
#include <cstddef> //size_t
#include "standard_types.hpp"
#include "storage.hpp"
#include "named_args.hpp"
#include "internal_types.hpp"
namespace rexy::fmt::detail{
template<class T>
struct valid_dynamic_index{
static constexpr bool value = std::is_convertible_v<T,long long> && !std::is_floating_point_v<T>;
};
template<class T>
static constexpr bool valid_dynamic_index_v = valid_dynamic_index<T>::value;
template<class T>
struct is_char_or_bool : public std::false_type{};
template<>
struct is_char_or_bool<bool> : public std::true_type{};
template<>
struct is_char_or_bool<char> : public std::true_type{};
template<>
struct is_char_or_bool<wchar_t> : public std::true_type{};
template<class T>
concept Integral = std::integral<T> && !is_char_or_bool<T>::value;
template<class T>
concept Bool = std::is_same_v<std::remove_cvref_t<T>,bool>;
template<class T>
concept Floating = std::floating_point<T>;
template<class T>
concept Arithmetic = Integral<T> || Floating<T>;
template<class T, class FmtCtx>
concept Handle = std::is_same_v<std::remove_cvref_t<T>,typename basic_format_arg<FmtCtx>::handle>;
template<class T>
concept Formatter_Char = std::is_same_v<T,char> || std::is_same_v<T,wchar_t>;
template<class T, class FmtCtx>
struct is_handle{
static constexpr bool value = Handle<T,FmtCtx>;
};
template<class T, class FmtCtx>
static constexpr bool is_handle_v = is_handle<T,FmtCtx>::value;
template<class T>
struct extract_char_type_from_context;
template<class OutIt, class Char>
struct extract_char_type_from_context<basic_format_context<OutIt,Char>>{
using type = Char;
};
template<class T>
using extract_char_type_from_context_t = typename extract_char_type_from_context<T>::type;
template<std::size_t I, class FmtCtx, class Arg, class... Args>
constexpr bool is_dynamic_integer_impl(int index){
using mapped_t = stored_type_t<Arg,FmtCtx>;
if(index == I){
return valid_dynamic_index_v<mapped_t>;
}
if constexpr(sizeof...(Args) > 0){
return is_dynamic_integer_impl<I+1,FmtCtx,Args...>(index);
}
return false;
}
template<class Char, class... Args>
constexpr bool is_dynamic_integer(int index){
using fmt_ctx_t = fmt_context_t<Char>;
if constexpr(sizeof...(Args) == 0){
return false;
}else{
return is_dynamic_integer_impl<0,fmt_ctx_t,Args...>(index);
}
}
static constexpr unsigned char utf_test[] = "\u00B5";
constexpr bool is_utf8(void){
using uchar = unsigned char;
return (sizeof(utf_test) == 3) && (uchar(utf_test[0]) == 0xC2) && (uchar(utf_test[1]) == 0xB5);
}
static constexpr wchar_t wutf_test[] = L"\U00010437";
constexpr bool is_wutf16(void){
return (sizeof(wutf_test) / sizeof(wutf_test[0]) == 3 &&
wutf_test[0] == 0xD801 && wutf_test[1] == 0xDC37);
}
constexpr bool is_wutf32(void){
return (sizeof(wutf_test) / sizeof(wutf_test[0]) == 2 &&
wutf_test[0] == 0x00010437);
}
template<class T>
struct is_utf8_encoded_string_type : public std::false_type{};
template<>
struct is_utf8_encoded_string_type<char8_t> : public std::true_type{};
template<>
struct is_utf8_encoded_string_type<char> : public std::integral_constant<bool,is_utf8()>{};
template<class T>
static constexpr bool is_utf8_encoded_string_type_v = is_utf8_encoded_string_type<T>::value;
template<class T>
struct is_utf16_encoded_string_type : public std::false_type{};
template<>
struct is_utf16_encoded_string_type<char16_t> : public std::true_type{};
template<>
struct is_utf16_encoded_string_type<wchar_t> : public std::integral_constant<bool,is_wutf16()>{};
template<class T>
static constexpr bool is_utf16_encoded_string_type_v = is_utf16_encoded_string_type<T>::value;
template<class T>
struct is_utf32_encoded_string_type : public std::false_type{};
template<>
struct is_utf32_encoded_string_type<char32_t> : public std::true_type{};
template<>
struct is_utf32_encoded_string_type<wchar_t> : public std::integral_constant<bool,is_wutf32()>{};
template<class T>
static constexpr bool is_utf32_encoded_string_type_v = is_utf32_encoded_string_type<T>::value;
template<class T>
concept UTF8_String = is_utf8_encoded_string_type_v<T>;
template<class T>
concept UTF16_String = is_utf16_encoded_string_type_v<T>;
template<class T>
concept UTF32_String = is_utf32_encoded_string_type_v<T>;
}
#endif

View File

@ -1,91 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_DETAIL_FORMAT_UTF_ITERATOR_TPP
#define REXY_DETAIL_FORMAT_UTF_ITERATOR_TPP
namespace rexy::fmt::detail{
template<class Char>
class utf8_iterator
{
private:
const Char* m_start = nullptr;
const Char* m_last = nullptr;
const Char* m_next = nullptr;
char32_t m_value = 0;
public:
constexpr utf8_iterator(const Char* first, const Char* last):
m_start(first), m_last(last)
{
m_next = convert_codepoint(m_start, m_last, m_value);
}
constexpr utf8_iterator& operator++(void){
m_start = m_next;
if(m_start != m_last){
m_next = convert_codepoint(m_start, m_last, m_value);
}
return *this;
}
constexpr utf8_iterator operator++(int){
auto tmp = *this;
++(*this);
return tmp;
}
constexpr char32_t operator*(void)const{
return m_value;
}
constexpr bool valid(void)const{
return m_start != m_last;
}
constexpr std::size_t byte_count(void)const{
return m_next - m_start;
}
private:
static constexpr const Char* convert_codepoint(const Char* first, const Char* last, char32_t& codepoint){
const std::size_t maxlen = last - first;
if((*first & 0x80) == 0){
codepoint = first[0];
return first + 1;
}else if((*first & 0xE0) == 0xC0 && maxlen > 1){
codepoint = ((first[0] & 0x1F) << 6);
codepoint += (first[1] & 0x3F);
return first + 2;
}else if((*first & 0xF0) == 0xE0 && maxlen > 2){
codepoint = ((first[0] & 0x0F) << 12);
codepoint += ((first[1] & 0x3F) << 6);
codepoint += (first[2] & 0x3F);
return first + 3;
}else if((*first & 0xF8) == 0xF0 && maxlen > 3){
codepoint = ((first[0] & 0x07) << 18);
codepoint += ((first[1] & 0x3F) << 12);
codepoint += (first[2] & 0x3F) << 6;
codepoint += (first[3] & 0x3F);
return first + 4;
}
codepoint = 0;
return first;
}
};
}
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,24 +19,28 @@
#ifndef REXY_DETAIL_HASALLOCATOR_HPP #ifndef REXY_DETAIL_HASALLOCATOR_HPP
#define REXY_DETAIL_HASALLOCATOR_HPP #define REXY_DETAIL_HASALLOCATOR_HPP
#include "../compat/standard.hpp"
#include "../allocator.hpp"
#include <type_traits> //is_empty
namespace rexy::detail{ namespace rexy::detail{
template<REXY_ALLOCATOR_CONCEPT Alloc> template<class Alloc>
struct hasallocator : public Alloc{ struct hasallocator
using Alloc::Alloc; {
using Alloc::operator=; Alloc m_alloc;
constexpr Alloc& allocator(void){
return *this; auto allocate(typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.allocate(0))){
return m_alloc.allocate(bytes);
} }
constexpr const Alloc& allocator(void)const{ void deallocate(typename Alloc::pointer p, typename Alloc::size_type bytes)noexcept(noexcept(m_alloc.deallocate(nullptr,0))){
return *this; m_alloc.deallocate(p, bytes);
}
Alloc& allocator(void){
return m_alloc;
}
const Alloc& allocator(void)const{
return m_alloc;
} }
}; };
} }
#endif #endif

View File

@ -20,8 +20,8 @@
#define REXY_STRING_APPENDER_HPP #define REXY_STRING_APPENDER_HPP
#include "../expression.hpp" #include "../expression.hpp"
#include "../traits.hpp"
#include <utility> //forward #include <utility> //forward
#include <type_traits> //enable_if, declval
namespace rexy::detail{ namespace rexy::detail{
@ -49,7 +49,12 @@ namespace rexy::detail{
template<class Val, std::enable_if_t<!rexy::is_template_derived_type<Val,binary_expression>::value,int> = 0, class = decltype(std::declval<Val>().length())> template<class Val, std::enable_if_t<!rexy::is_template_derived_type<Val,binary_expression>::value,int> = 0, class = decltype(std::declval<Val>().length())>
constexpr void operator()(Val&& v) constexpr void operator()(Val&& v)
{ {
m_targ.append(std::forward<Val>(v).data(), std::forward<Val>(v).length()); m_targ.append(std::forward<Val>(v).get(), std::forward<Val>(v).length());
}
template<class Val, std::enable_if_t<!rexy::is_template_derived_type<Val,binary_expression>::value,void*> = nullptr, class = decltype(std::declval<Val>().size())>
constexpr void operator()(Val&& v)
{
m_targ.append(std::forward<Val>(v).get(), std::forward<Val>(v).size());
} }
}; };

View File

@ -1,215 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//requires c++20
#ifndef REXY_ENUM_CLASS_HPP
#define REXY_ENUM_CLASS_HPP
#include "compat/standard.hpp"
#ifndef __cpp_concepts
#error "Cannot use enum_traits without C++20 concept support"
#else //__cpp_concepts
#include <type_traits>
template<class T>
concept Scoped_Enum = requires{
typename std::underlying_type_t<T>;
requires std::is_enum_v<T>;
requires !std::is_convertible_v<T, std::underlying_type_t<T>>;
};
//since std::to_underlying is only available since c++23
namespace rexy::enum_traits{
template<Scoped_Enum E>
constexpr std::underlying_type_t<E> to_underlying(E t)noexcept{
return static_cast<std::underlying_type_t<E>>(t);
}
}
template<Scoped_Enum E>
constexpr E operator|(E t, E t2)noexcept{
return static_cast<E>(rexy::enum_traits::to_underlying(t) | rexy::enum_traits::to_underlying(t2));
}
template<Scoped_Enum E>
constexpr E& operator|=(E& t, E t2)noexcept{
t = static_cast<E>(rexy::enum_traits::to_underlying(t) | rexy::enum_traits::to_underlying(t2));
return t;
}
template<Scoped_Enum E>
constexpr E operator&(E t, E t2)noexcept{
return static_cast<E>(rexy::enum_traits::to_underlying(t) & rexy::enum_traits::to_underlying(t2));
}
template<Scoped_Enum E>
constexpr E& operator&=(E& t, E t2)noexcept{
t = static_cast<E>(rexy::enum_traits::to_underlying(t) & rexy::enum_traits::to_underlying(t2));
return t;
}
template<Scoped_Enum E>
constexpr E operator^(E t, E t2)noexcept{
return static_cast<E>(rexy::enum_traits::to_underlying(t) ^ rexy::enum_traits::to_underlying(t2));
}
template<Scoped_Enum E>
constexpr E& operator^=(E& t, E t2)noexcept{
t = static_cast<E>(rexy::enum_traits::to_underlying(t) ^ rexy::enum_traits::to_underlying(t2));
return t;
}
template<Scoped_Enum E>
constexpr E operator!(E t)noexcept{
return static_cast<E>(!(rexy::enum_traits::to_underlying(t)));
}
template<Scoped_Enum E>
constexpr E operator~(E t)noexcept{
return static_cast<E>(~rexy::enum_traits::to_underlying(t));
}
template<Scoped_Enum E>
constexpr E operator<<(E t, int shift)noexcept{
return static_cast<E>(rexy::enum_traits::to_underlying(t) << shift);
}
template<Scoped_Enum E>
constexpr E& operator<<=(E& t, int shift)noexcept{
t = static_cast<E>(rexy::enum_traits::to_underlying(t) << shift);
return t;
}
template<Scoped_Enum E>
constexpr E operator>>(E t, int shift)noexcept{
return static_cast<E>(rexy::enum_traits::to_underlying(t) >> shift);
}
template<Scoped_Enum E>
constexpr E& operator>>=(E& t, int shift)noexcept{
t = static_cast<E>(rexy::enum_traits::to_underlying(t) >> shift);
return t;
}
template<Scoped_Enum E>
constexpr bool operator>(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) > rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator>(E t, std::underlying_type_t<E> u){
return rexy::enum_traits::to_underlying(t) > u;
}
template<Scoped_Enum E>
constexpr bool operator<(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) < rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator<(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) < u;
}
template<Scoped_Enum E>
constexpr bool operator>=(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) >= rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator>=(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) >= u;
}
template<Scoped_Enum E>
constexpr bool operator<=(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) <= rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator<=(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) <= u;
}
template<Scoped_Enum E>
constexpr bool operator==(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) == rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator==(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) == u;
}
template<Scoped_Enum E>
constexpr bool operator!=(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) != rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool operator!=(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) != u;
}
namespace rexy::enum_traits{
template<Scoped_Enum E>
constexpr bool not_zero(E t)noexcept{
return rexy::enum_traits::to_underlying(t) != 0;
}
template<Scoped_Enum E>
constexpr bool is_zero(E t)noexcept{
return rexy::enum_traits::to_underlying(t) == 0;
}
template<Scoped_Enum E>
constexpr bool is_greater_than(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) > rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_greater_than(E t, std::underlying_type_t<E> u){
return rexy::enum_traits::to_underlying(t) > u;
}
template<Scoped_Enum E>
constexpr bool is_less_than(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) < rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_less_than(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) < u;
}
template<Scoped_Enum E>
constexpr bool is_greater_than_equal(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) >= rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_greater_than_equal(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) >= u;
}
template<Scoped_Enum E>
constexpr bool is_less_than_equal(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) <= rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_less_than_equal(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) <= u;
}
template<Scoped_Enum E>
constexpr bool is_equal(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) == rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_equal(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) == u;
}
template<Scoped_Enum E>
constexpr bool is_not_equal(E t1, E t2)noexcept{
return rexy::enum_traits::to_underlying(t1) != rexy::enum_traits::to_underlying(t2);
}
template<Scoped_Enum E>
constexpr bool is_not_equal(E t, std::underlying_type_t<E> u)noexcept{
return rexy::enum_traits::to_underlying(t) != u;
}
}
#endif //__cpp_concepts
#endif

View File

@ -19,7 +19,7 @@
#ifndef REXY_EXPRESSION_HPP #ifndef REXY_EXPRESSION_HPP
#define REXY_EXPRESSION_HPP #define REXY_EXPRESSION_HPP
#include <type_traits> //is_void, remove_reference, conditional #include <type_traits>
#include <utility> //forward #include <utility> //forward
#include "rexy.hpp" #include "rexy.hpp"
@ -29,8 +29,8 @@ namespace rexy{
template<class L, class R> template<class L, class R>
class binary_expression class binary_expression
{ {
static_assert(!std::is_void_v<L>, "Left value of rexy::binary_expression cannot be void!"); static_assert(!std::is_same<std::decay_t<L>,void>::value, "Left value of rexy::binary_expression cannot be void!");
static_assert(!std::is_void_v<R>, "Right value of rexy::binary_expression cannot be void!"); static_assert(!std::is_same<std::decay_t<R>,void>::value, "Right value of rexy::binary_expression cannot be void!");
public: public:
using left_type = std::conditional_t<std::is_rvalue_reference<L>::value, using left_type = std::conditional_t<std::is_rvalue_reference<L>::value,
@ -78,7 +78,7 @@ namespace rexy{
template<class L> template<class L>
class unary_expression class unary_expression
{ {
static_assert(!std::is_void_v<L>, "Value of rexy::unary_expression cannot be void!"); static_assert(!std::is_same<std::decay_t<L>,void>::value, "Value of rexy::unary_expression cannot be void!");
public: public:
using left_type = std::conditional_t<std::is_rvalue_reference<L>::value, using left_type = std::conditional_t<std::is_rvalue_reference<L>::value,

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -19,18 +19,15 @@
#ifndef REXY_FILERD_HPP #ifndef REXY_FILERD_HPP
#define REXY_FILERD_HPP #define REXY_FILERD_HPP
#ifndef LIBREXY_HEADER_ONLY
#include <cstdio> //FILE #include <cstdio> //FILE
#include <cstddef> //size_t #include <cstddef> //size_t
#include <type_traits> //is_nothrow_constructible #include <type_traits> //is_nothrow_constructible
#include "string.hpp" #include "string.hpp"
#include "steal.hpp" #include "steal.hpp"
#include "binary.hpp"
#include "utility.hpp" #include "utility.hpp"
#include "rexy.hpp" #include "rexy.hpp"
#include "buffer.hpp"
#include "string_view.hpp"
namespace rexy{ namespace rexy{
@ -38,8 +35,7 @@ namespace rexy{
class filerd class filerd
{ {
private: private:
std::FILE* m_fp = nullptr; FILE* m_fp = nullptr;
bool m_finished = false;
public: public:
constexpr filerd(void)noexcept = default; constexpr filerd(void)noexcept = default;
@ -50,39 +46,31 @@ namespace rexy{
~filerd(void)noexcept; ~filerd(void)noexcept;
filerd& operator=(const filerd&) = delete; filerd& operator=(const filerd&) = delete;
constexpr filerd& operator=(filerd&& f)noexcept{ constexpr filerd& operator=(filerd&& f)noexcept{
rexy::swap(m_fp, f.m_fp); swap(m_fp, f.m_fp);
return *this; return *this;
} }
void reset(std::FILE* fp = nullptr)noexcept; void reset(FILE* fp = nullptr)noexcept;
std::FILE* release(void)noexcept; FILE* release(void)noexcept;
std::size_t length(void)noexcept; size_t length(void)noexcept;
std::size_t position(void)const noexcept; size_t position(void)const noexcept;
void rewind(std::size_t pos = 0)noexcept; void rewind(size_t pos = 0)noexcept;
operator std::FILE*(void)noexcept; operator FILE*(void)noexcept;
operator const std::FILE*(void)const noexcept; operator const FILE*(void)const noexcept;
std::FILE* get(void)noexcept; FILE* get(void)noexcept;
const std::FILE* get(void)const noexcept; const FILE* get(void)const noexcept;
operator bool(void)const noexcept; operator bool(void)const noexcept;
bool eof(void)const; size_t read(char* dest, size_t bytes)noexcept;
rexy::string read(size_t bytes)noexcept;
rexy::string readln(size_t max = 0)noexcept;
rexy::binary read_bin(size_t bytes)noexcept(std::is_nothrow_constructible<rexy::binary, rexy::steal<char*>, size_t, size_t>::value);
std::size_t read(char* dest, std::size_t bytes)noexcept; size_t write(const char* c, size_t bytes)noexcept;
rexy::string read(std::size_t bytes)noexcept; size_t write(const rexy::string_base<char>& s)noexcept;
rexy::string readln(std::size_t max = 0)noexcept;
rexy::buffer<char> read_bin(std::size_t bytes)noexcept(std::is_nothrow_constructible<rexy::buffer<char>, char*, std::size_t>::value);
std::size_t write(const char* c, std::size_t bytes)noexcept;
std::size_t write(rexy::string_view s)noexcept;
}; };
} }
#else //LIBREXY_HEADER_ONLY
#error "rexy::filerd is not available when built with header only support"
#endif //LIBREXY_HEADER_ONLY
#endif #endif

View File

@ -1,157 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_FORMAT_HPP
#define REXY_FORMAT_HPP
#include "string.hpp"
#include "string_view.hpp"
#include "compat/standard.hpp"
REXY_REQUIRES_CPP20;
#ifndef REXY_STANDARD_CPP20
//Maybe I'll make it work someday, but not for now
#error "Cannot use formatting library without C++20 support"
#endif
#include "detail/format/standard_types.hpp"
#include "detail/format/internal_types.hpp"
#include "detail/format/arg_store.hpp"
#include "detail/format/format_string.hpp"
#include "detail/format/format_args.hpp"
#include "detail/format/format_error.hpp"
#include <cstdio> //FILE
#include <cstddef> //size_t
#include <locale> //locale
namespace rexy{
//Alias declarations of standard defined types
using format_context = fmt::detail::fmt_context_t<char>;
using wformat_context = fmt::detail::fmt_context_t<wchar_t>;
using parse_context = fmt::detail::parse_context_t<char>;
using wparse_context = fmt::detail::parse_context_t<wchar_t>;
using format_arg = fmt::basic_format_arg<format_context>;
using wformat_arg = fmt::basic_format_arg<wformat_context>;
using format_args = fmt::basic_format_args<format_context>;
using wformat_args = fmt::basic_format_args<wformat_context>;
template<class Context = format_context, class... Args>
fmt::detail::basic_format_arg_store<Context,Args...> make_format_args(Args&&... args);
template<class Context = wformat_context, class... Args>
fmt::detail::basic_format_arg_store<Context,Args...> make_wformat_args(Args&&... args);
template<class OutIt>
OutIt vformat_to(OutIt out, string_view fmt, format_args args);
template<class OutIt>
OutIt vformat_to(OutIt out, const std::locale& loc, string_view fmt, wformat_args args);
string vformat(string_view fmt, format_args args);
string vformat(const std::locale& loc, string_view fmt, format_args args);
template<class OutIt, class... Args>
OutIt format_to(OutIt out, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
OutIt format_to(OutIt out, const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, std::size_t max, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, const std::locale& loc, std::size_t max, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
string format(fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
string format(const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t formatted_size(fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t formatted_size(const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class OutIt>
OutIt vformat_to(OutIt out, wstring_view fmt, wformat_args args);
template<class OutIt>
OutIt vformat_to(OutIt out, const std::locale& loc, wstring_view fmt, wformat_args args);
wstring vformat(wstring_view fmt, format_args args);
wstring vformat(const std::locale& loc, wstring_view fmt, wformat_args args);
template<class OutIt, class... Args>
OutIt format_to(OutIt out, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
OutIt format_to(OutIt out, const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, std::size_t max, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, const std::locale& loc, std::size_t max, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
wstring format(fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
wstring format(const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t formatted_size(fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t formatted_size(const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t print(fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t print(FILE* stream, fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t println(fmt::detail::format_string<Args...> fmt, Args&&... args);
template<class... Args>
std::size_t println(FILE* stream, fmt::detail::format_string<Args...> fmt, Args&&... args);
std::size_t vprint_unicode(string_view fmt, format_args args);
std::size_t vprint_unicode(FILE* stream, string_view fmt, format_args args);
template<class T, class Char>
constexpr auto arg(const Char* name, T&& t);
template<class T, class Char>
constexpr auto arg(rexy::basic_string_view<Char> name, T&& t);
template<rexy::cx::string Name, class T>
constexpr auto arg(T&& t);
inline namespace fmt_literals{
template<rexy::cx::string Name>
constexpr auto operator""_a(void);
}
}
#include "format.tpp"
#endif

View File

@ -1,340 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_FORMAT_TPP
#define REXY_FORMAT_TPP
REXY_REQUIRES_CPP20;
#include "detail/format/format_args.tpp"
#include "detail/format/formatter.tpp"
#include "detail/format/storage.tpp"
#include "detail/format/format_string.tpp"
#include "detail/format/arg_store.tpp"
#include "detail/format/output_buffer.tpp"
#include "detail/format/basic_types.tpp"
#include "detail/format/specs_handler.tpp"
#include "detail/format/parse.tpp"
#include "detail/format/context_handler.tpp"
#include "detail/format/named_args.tpp"
#include "detail/format/parse_context.tpp"
#include "detail/format/format_context.tpp"
#include <iterator> //back_insert_iterator
#include <utility> //move, forward
#include <type_traits> //is_same
#include <locale> //locale
#include <cstddef> //size_t
namespace rexy{
namespace fmt::detail{
template<class Char, class OutIt>
OutIt vformat_to(OutIt out, basic_string_view<std::type_identity_t<Char>> fmt, impl_format_args<std::type_identity_t<Char>> args){
using char_type = Char;
using format_handler_t = fmt::detail::format_handler<char_type>;
if constexpr(std::is_same_v<OutIt,fmt::detail::output_iterator_t<char_type>>){
fmt::detail::format_handler<char_type> handler{out, fmt, args};
fmt::detail::parse::perform_parse(handler, fmt);
return std::move(out);
}else{
fmt::detail::basic_format_output_buffer<char_type,OutIt> outbuf{out};
fmt::detail::format_handler<char_type> handler{fmt::detail::output_iterator_t<char_type>{outbuf}, fmt, args};
fmt::detail::parse::perform_parse(handler, fmt);
return std::move(outbuf.out());
}
}
template<class Char, class OutIt>
OutIt vformat_to(OutIt out, const std::locale& loc, basic_string_view<std::type_identity_t<Char>> fmt, impl_format_args<std::type_identity_t<Char>> args){
using char_type = Char;
using format_handler_t = fmt::detail::format_handler<char_type>;
if constexpr(std::is_same_v<OutIt,fmt::detail::output_iterator_t<char_type>>){
fmt::detail::format_handler<char_type> handler{out, fmt, args, loc};
fmt::detail::parse::perform_parse(handler, fmt);
return std::move(out);
}else{
fmt::detail::basic_format_output_buffer<char_type,OutIt> outbuf{out};
fmt::detail::format_handler<char_type> handler{fmt::detail::output_iterator_t<char_type>{outbuf}, fmt, args, loc};
fmt::detail::parse::perform_parse(handler, fmt);
return std::move(outbuf.out());
}
}
template<class Char, class... Args>
basic_format_arg_store<fmt_context_t<Char>,Args...> make_format_args(Args&&... args){
return basic_format_arg_store<fmt_context_t<Char>,Args...>{std::forward<Args>(args)...};
}
}
template<class Context, class... Args>
fmt::detail::basic_format_arg_store<Context,Args...> make_format_args(Args&&... args){
return fmt::detail::basic_format_arg_store<Context,Args...>{std::forward<Args>(args)...};
}
template<class Context, class... Args>
fmt::detail::basic_format_arg_store<Context,Args...> make_wformat_args(Args&&... args){
return fmt::detail::basic_format_arg_store<Context,Args...>{std::forward<Args>(args)...};
}
//////////////////////////////////////char overloads///////////////////////////////////////////////
template<class OutIt>
OutIt vformat_to(OutIt out, string_view fmt, format_args args){
return fmt::detail::vformat_to<char>(std::move(out), fmt, std::move(args));
}
template<class OutIt>
OutIt vformat_to(OutIt out, const std::locale& loc, string_view fmt, format_args args){
return fmt::detail::vformat_to<char>(std::move(out), loc, fmt, std::move(args));
}
string vformat(string_view fmt, format_args args){
using outit_t = std::back_insert_iterator<string>;
string output;
outit_t out{output};
vformat_to(std::move(out), fmt, std::move(args));
return output;
}
string vformat(const std::locale& loc, string_view fmt, format_args args){
using outit_t = std::back_insert_iterator<string>;
string output;
outit_t out{output};
vformat_to(std::move(out), loc, fmt, std::move(args));
return output;
}
template<class OutIt, class... Args>
OutIt format_to(OutIt out, fmt::detail::format_string<Args...> fmt, Args&&... args){
return vformat_to(std::move(out), fmt.str, make_format_args(std::forward<Args>(args)...));
}
template<class OutIt, class... Args>
OutIt format_to(OutIt out, const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args){
return vformat_to(std::move(out), loc, fmt.str, make_format_args(std::forward<Args>(args)...));
}
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, std::size_t max, fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_output_n_buffer<char,OutIt> outbuf{std::move(out), max};
vformat_to(fmt::detail::output_iterator_t<char>{outbuf}, fmt.str, make_format_args(std::forward<Args>(args)...));
return {outbuf.out(), outbuf.count()};
}
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, const std::locale& loc, std::size_t max, fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_output_n_buffer<char,OutIt> outbuf{std::move(out), max};
vformat_to(fmt::detail::output_iterator_t<char>{outbuf}, loc, fmt.str, make_format_args(std::forward<Args>(args)...));
return {outbuf.out(), outbuf.count()};
}
template<class... Args>
string format(fmt::detail::format_string<Args...> fmt, Args&&... args){
using outit_t = std::back_insert_iterator<string>;
string output;
outit_t out{output};
vformat_to(std::move(out), fmt.str, make_format_args(std::forward<Args>(args)...));
return output;
}
template<class... Args>
string format(const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args){
using outit_t = std::back_insert_iterator<string>;
string output;
outit_t out{output};
vformat_to(std::move(out), loc, fmt.str, make_format_args(std::forward<Args>(args)...));
return output;
}
template<class... Args>
std::size_t formatted_size(fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_size_buffer<char> counter;
vformat_to(fmt::detail::output_iterator_t<char>{counter}, fmt.str, make_format_args(std::forward<Args>(args)...));
return counter.count();
}
template<class... Args>
std::size_t formatted_size(const std::locale& loc, fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_size_buffer<char> counter;
vformat_to(fmt::detail::output_iterator_t<char>{counter}, loc, fmt.str, make_format_args(std::forward<Args>(args)...));
return counter.count();
}
//////////////////////////////////////wchar_t overloads///////////////////////////////////////////////
template<class OutIt>
OutIt vformat_to(OutIt out, wstring_view fmt, wformat_args args){
return fmt::detail::vformat_to<wchar_t>(std::move(out), fmt, std::move(args));
}
template<class OutIt>
OutIt vformat_to(OutIt out, const std::locale& loc, wstring_view fmt, wformat_args args){
return fmt::detail::vformat_to<wchar_t>(std::move(out), loc, fmt, std::move(args));
}
wstring vformat(wstring_view fmt, wformat_args args){
using outit_t = std::back_insert_iterator<wstring>;
wstring output;
outit_t out{output};
vformat_to(std::move(out), fmt, std::move(args));
return output;
}
wstring vformat(const std::locale& loc, wstring_view fmt, wformat_args args){
using outit_t = std::back_insert_iterator<wstring>;
wstring output;
outit_t out{output};
vformat_to(std::move(out), loc, fmt, std::move(args));
return output;
}
template<class OutIt, class... Args>
OutIt format_to(OutIt out, fmt::detail::wformat_string<Args...> fmt, Args&&... args){
return vformat_to(std::move(out), fmt.str, make_wformat_args(std::forward<Args>(args)...));
}
template<class OutIt, class... Args>
OutIt format_to(OutIt out, const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args){
return vformat_to(std::move(out), loc, fmt.str, make_wformat_args(std::forward<Args>(args)...));
}
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, std::size_t max, fmt::detail::wformat_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_output_n_buffer<wchar_t,OutIt> outbuf{std::move(out), max};
vformat_to(fmt::detail::output_iterator_t<wchar_t>{outbuf}, fmt.str, make_wformat_args(std::forward<Args>(args)...));
return {outbuf.out(), outbuf.count()};
}
template<class OutIt, class... Args>
format_to_n_result<OutIt> format_to_n(OutIt out, const std::locale& loc, std::size_t max, fmt::detail::wformat_string<Args...> fmt, Args&&... args){
fmt::detail::basic_format_output_n_buffer<wchar_t,OutIt> outbuf{std::move(out), max};
vformat_to(fmt::detail::output_iterator_t<wchar_t>{outbuf}, loc, fmt.str, make_wformat_args(std::forward<Args>(args)...));
return {outbuf.out(), outbuf.count()};
}
template<class... Args>
wstring format(fmt::detail::wformat_string<Args...> fmt, Args&&... args){
using outit_t = std::back_insert_iterator<wstring>;
wstring output;
outit_t out{output};
vformat_to(out, fmt.str, make_wformat_args(std::forward<Args>(args)...));
return output;
}
template<class... Args>
wstring format(const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args){
using outit_t = std::back_insert_iterator<wstring>;
wstring output;
outit_t out{output};
vformat_to(out, fmt.str, make_wformat_args(std::forward<Args>(args)...));
return output;
}
template<class... Args>
std::size_t formatted_size(fmt::detail::wformat_string<Args...> fmt, Args&&... args){
}
template<class... Args>
std::size_t formatted_size(const std::locale& loc, fmt::detail::wformat_string<Args...> fmt, Args&&... args);
//////////////////////////////////////print char overloads///////////////////////////////////////////////
template<class... Args>
std::size_t print(fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::print_format_buffer<char> out{stdout};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt.str, make_format_args(std::forward<Args>(args)...));
return out.count();
}
template<class... Args>
std::size_t print(FILE* stream, fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::print_format_buffer<char> out{stream};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt.str, make_format_args(std::forward<Args>(args)...));
return out.count();
}
template<class... Args>
std::size_t println(fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::print_format_buffer<char> out{stdout};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt.str, make_format_args(std::forward<Args>(args)...));
out.push_back('\n');
return out.count();
}
template<class... Args>
std::size_t println(FILE* stream, fmt::detail::format_string<Args...> fmt, Args&&... args){
fmt::detail::print_format_buffer<char> out{stream};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt.str, make_format_args(std::forward<Args>(args)...));
out.push_back('\n');
return out.count();
}
std::size_t vprint_unicode(string_view fmt, format_args args){
fmt::detail::print_format_buffer<char> out{stdout};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt, args);
return out.count();
}
std::size_t vprint_unicode(FILE* stream, string_view fmt, format_args args){
fmt::detail::print_format_buffer<char> out{stream};
vformat_to(fmt::detail::output_iterator_t<char>{out}, fmt, args);
return out.count();
}
//creates a runtime argument from a c string
template<class T, class Char>
constexpr auto arg(const Char* name, T&& t){
return fmt::detail::runtime_arg<T,Char>{std::forward<T>(t), name};
}
//creates a runtime argument from a string view
template<class T, class Char>
constexpr auto arg(rexy::basic_string_view<Char> name, T&& t){
return fmt::detail::runtime_arg{std::forward<T>(t), name};
}
//create a compile time argument from a string literal
template<rexy::cx::string Name, class T>
constexpr auto arg(T&& t){
return fmt::detail::static_arg<T,Name>{t};
}
inline namespace fmt_literals{
//create a compile time argument from a string literal
template<rexy::cx::string Name>
constexpr auto operator""_a(void){
return fmt::detail::arg_literal_result<Name>{};
}
}
}
#undef REXY_REAL_STRINGIFY
#undef REXY_STRINGIFY
#undef REXY_THROW_FORMAT_ERROR
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -20,29 +20,17 @@
#define REXY_HASH_HPP #define REXY_HASH_HPP
#include <climits> //CHAR_BIT #include <climits> //CHAR_BIT
#include <cstddef> //size_t
#include "rexy.hpp" #include "rexy.hpp"
#include "allocator.hpp"
namespace rexy{ namespace rexy{
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
class basic_string;
template<class Char>
class basic_string_view;
namespace cx{
template<std::size_t N, class Char>
class string;
}
template<class T> template<class T>
struct hash{ struct hash{
constexpr std::size_t operator()(const T& t, std::size_t salt = 0)const noexcept{ constexpr size_t operator()(const T& t, size_t salt)const noexcept{
constexpr std::size_t bytes = sizeof(std::size_t); constexpr size_t bytes = sizeof(size_t);
std::size_t val = static_cast<std::size_t>(t); size_t val = static_cast<size_t>(t);
std::size_t hash = 5381 + salt; //magic hash number size_t hash = 5381 + salt; //magic hash number
for(std::size_t i = 0;i < bytes;++i){ for(size_t i = 0;i < bytes;++i){
unsigned char c = static_cast<unsigned char>(val >> (i * CHAR_BIT)); unsigned char c = static_cast<unsigned char>(val >> (i * CHAR_BIT));
hash = ((hash << 5) + hash) ^ c; hash = ((hash << 5) + hash) ^ c;
} }
@ -50,32 +38,16 @@ namespace rexy{
} }
}; };
namespace detail{
//jenkins one at a time hash
template<class Str>
struct string_hash{
constexpr std::size_t operator()(const Str& s, std::size_t salt = 0)const noexcept{
std::size_t hash = salt;
for(std::size_t i = 0;i < s.length();++i){
hash += s[i];
hash += (hash << 10);
hash += (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash << 11);
hash += (hash << 15);
return hash;
}
};
}
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc>
struct hash<rexy::basic_string<Char,Alloc>> : public detail::string_hash<rexy::basic_string<Char,Alloc>>{};
template<class Char>
struct hash<rexy::basic_string_view<Char>> : public detail::string_hash<rexy::basic_string_view<Char>>{};
template<std::size_t N, class Char>
struct hash<rexy::cx::string<N,Char>> : public detail::string_hash<rexy::cx::string<N,Char>>{};
} }
#ifdef REXY_STRING_BASE_HPP
#include "static_string_hash.hpp"
#endif
#ifdef REXY_STRING_HPP
#include "basic_string_hash.hpp"
#endif
#ifdef REXY_CX_STRING_HPP
#include "cx_string_hash.hpp"
#endif
#endif #endif

View File

@ -1,400 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_LLIST_HPP
#define REXY_LLIST_HPP
#include <cstddef> //size_t, ptrdiff_t
#include "allocator.hpp"
#include "detail/hasallocator.hpp"
#include "traits.hpp"
#include <iterator> //bidirectional_iterator_tag, reverse_iterator
#include <memory> //allocator_traits
#include <initializer_list>
#include <utility> //pair
#include <type_traits>
namespace rexy{
template<class T, class Alloc>
class list;
namespace detail{
struct list_node_base{
list_node_base* next = nullptr;
list_node_base* prev = nullptr;
};
template<class T>
struct list_iterator;
template<class T>
struct const_list_iterator;
template<class T>
struct list_node;
}
template<class T, class Alloc = rexy::allocator<T>>
class list : protected detail::hasallocator<typename std::allocator_traits<Alloc>::template rebind_alloc<detail::list_node<T>>>
{
private:
using node_allocator_type = detail::hasallocator<typename std::allocator_traits<Alloc>::template rebind_alloc<detail::list_node<T>>>;
public:
using value_type = T;
using allocator_type = Alloc;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator = detail::list_iterator<T>;
using const_iterator = detail::const_list_iterator<T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public:
using node = detail::list_node<T>;
private:
detail::list_node_base m_sentinel = {&m_sentinel, &m_sentinel};
size_type m_size = 0;
public:
constexpr list(void)noexcept = default;
constexpr explicit list(const allocator_type& alloc)noexcept;
REXY_CPP20_CONSTEXPR
list(size_type count, const_reference value = value_type(), const allocator_type& = allocator_type())noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
explicit list(size_type count, const allocator_type& alloc = allocator_type())noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class InputIt>
REXY_CPP20_CONSTEXPR
list(InputIt first, InputIt last, const allocator_type& alloc = allocator_type())noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
list(const list& other, const allocator_type& alloc = allocator_type())noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
list(list&& other, const allocator_type& alloc = allocator_type())noexcept;
REXY_CPP20_CONSTEXPR
list(std::initializer_list<value_type> l, const allocator_type& alloc = allocator_type())noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
~list(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
list& operator=(const list& other)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
list& operator=(list&& other)noexcept;
REXY_CPP20_CONSTEXPR
list& operator=(std::initializer_list<value_type> l)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>);
constexpr bool operator==(const list& other)const noexcept;
#if __cpp_impl_three_way_comparison
constexpr auto operator<=>(const list& other)const noexcept;
#else
constexpr bool operator!=(const list& other)const noexcept;
constexpr bool operator<(const list& other)const noexcept;
constexpr bool operator<=(const list& other)const noexcept;
constexpr bool operator>(const list& other)const noexcept;
constexpr bool operator>=(const list& other)const noexcept;
#endif
REXY_CPP20_CONSTEXPR
void assign(size_type count, const_reference value)noexcept(
std::conditional_t<
std::is_copy_assignable_v<value_type>,
std::is_nothrow_copy_assignable<value_type>,
std::true_type>::value &&
std::is_nothrow_copy_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class InputIt>
REXY_CPP20_CONSTEXPR
void assign(InputIt first, InputIt last)noexcept(
std::conditional_t<
std::is_assignable_v<value_type, decltype(*first)>,
std::is_nothrow_assignable<value_type, decltype(*first)>,
std::true_type>::value &&
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void assign(std::initializer_list<value_type> l)noexcept(
std::conditional_t<
std::is_assignable_v<value_type, decltype(*l.begin())>,
std::is_nothrow_assignable<value_type, decltype(*l.begin())>,
std::true_type>::value &&
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
constexpr allocator_type get_allocator(void)const noexcept;
constexpr reference front(void)noexcept;
constexpr const_reference front(void)const noexcept;
constexpr reference back(void)noexcept;
constexpr const_reference back(void)const noexcept;
constexpr iterator begin(void)noexcept;
constexpr const_iterator begin(void)const noexcept;
constexpr const_iterator cbegin(void)const noexcept;
constexpr iterator end(void)noexcept;
constexpr const_iterator end(void)const noexcept;
constexpr const_iterator cend(void)const noexcept;
constexpr iterator next(iterator i)noexcept;
constexpr const_iterator next(const_iterator i)noexcept;
constexpr iterator prev(iterator i)noexcept;
constexpr const_iterator prev(const_iterator i)noexcept;
constexpr reverse_iterator rbegin(void)noexcept;
constexpr const_reverse_iterator rbegin(void)const noexcept;
constexpr const_reverse_iterator crbegin(void)const noexcept;
constexpr reverse_iterator rend(void)noexcept;
constexpr const_reverse_iterator rend(void)const noexcept;
constexpr const_reverse_iterator crend(void)const noexcept;
constexpr bool empty(void)const noexcept;
constexpr size_type size(void)const noexcept;
constexpr size_type max_size(void)const noexcept;
REXY_CPP20_CONSTEXPR
void clear(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator insert(const_iterator pos, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator insert(const_iterator pos, value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator insert(const_iterator pos, size_type count, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class InputIt>
REXY_CPP20_CONSTEXPR
iterator insert(const_iterator pos, InputIt first, InputIt last)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator insert(const_iterator pos, std::initializer_list<value_type> l)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class... Args>
REXY_CPP20_CONSTEXPR
iterator emplace(const_iterator pos, Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator erase(const_iterator pos)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
iterator erase(const_iterator first, const_iterator last)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
reference push_back(const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
reference push_back(value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class... Args>
REXY_CPP20_CONSTEXPR
reference emplace_back(Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void pop_back(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
reference push_front(const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
reference push_front(value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class... Args>
REXY_CPP20_CONSTEXPR
reference emplace_front(Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void pop_front(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void resize(size_type count)noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void resize(size_type count, value_type value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void swap(list& other)noexcept;
REXY_CPP20_CONSTEXPR
void merge(list&& other)noexcept;
template<class Comp>
REXY_CPP20_CONSTEXPR
void merge(list&& other, Comp comp)noexcept;
REXY_CPP20_CONSTEXPR
void splice(const_iterator pos, list&& other)noexcept;
REXY_CPP20_CONSTEXPR
void splice(const_iterator pos, list&& other, const_iterator it)noexcept;
REXY_CPP20_CONSTEXPR
void splice(const_iterator pos, list&& other, const_iterator first, const_iterator last)noexcept;
REXY_CPP20_CONSTEXPR
size_type remove(const_reference value)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class UnaryPred>
REXY_CPP20_CONSTEXPR
size_type remove_if(UnaryPred p)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void reverse(void)noexcept;
REXY_CPP20_CONSTEXPR
size_type unique(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class BinaryPred>
REXY_CPP20_CONSTEXPR
size_type unique(BinaryPred p)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void sort(void)noexcept;
template<class Comp>
REXY_CPP20_CONSTEXPR
void sort(Comp comp)noexcept;
private:
template<class InputIt>
REXY_CPP20_CONSTEXPR
void iterator_initialize_(InputIt first, InputIt last)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void constant_initialize_(size_type count, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
REXY_CPP20_CONSTEXPR
void default_initialize_(size_type count)noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>);
template<class Comp>
static iterator mergesort(iterator first, size_type firstlen, Comp comp)noexcept;
static std::pair<iterator,size_type> ms_split(iterator it, size_type len)noexcept;
static void insert_node_(detail::list_node_base* prev, detail::list_node_base* n)noexcept;
static void remove_node_(detail::list_node_base* rm)noexcept;
static detail::list_node_base* get_next_then_move_node_(detail::list_node_base* dest, detail::list_node_base* n)noexcept;
};
}
#include "list.tpp"
#endif

View File

@ -1,861 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_LLIST_TPP
#define REXY_LLIST_TPP
#include <utility> //move, swap, forward
#include <limits> //numeric_limits
#include <algorithm> //lexicographical_compare_three_way, equal
#include <memory> //construct_at, destroy_at
#include "utility.hpp" //sized_constant_iterator
namespace rexy{
namespace detail{
template<class T>
struct list_node : public list_node_base{
T data;
constexpr list_node(list_node_base* next, list_node_base* prev, const T& d):
list_node_base{next, prev},
data(d){}
constexpr list_node(list_node_base* next, list_node_base* prev, T&& d):
list_node_base{next, prev},
data(std::move(d)){}
template<class... Args>
constexpr list_node(list_node_base* next, list_node_base* prev, Args&&... args):
list_node_base{next, prev},
data(std::forward<Args>(args)...){}
constexpr list_node(const list_node& n):
list_node_base(n),
data(n.data){}
constexpr list_node(list_node&& n):
list_node_base(std::move(n)),
data(std::move(n.data)){}
constexpr list_node* next(void)const{return static_cast<list_node*>(list_node_base::next);}
constexpr list_node* prev(void)const{return static_cast<list_node*>(list_node_base::prev);}
};
template<class T>
struct list_iterator{
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using node_t = list_node<T>;
list_node_base* current = nullptr;
constexpr bool operator==(const list_iterator& other)const noexcept{return current == other.current;}
constexpr bool operator!=(const list_iterator& other)const noexcept{return current != other.current;}
constexpr bool operator==(const const_list_iterator<T>& other)const noexcept{return current == other.nod();}
constexpr bool operator!=(const const_list_iterator<T>& other)const noexcept{return current != other.nod();}
constexpr reference operator*(void){return static_cast<node_t*>(current)->data;}
constexpr const_reference operator*(void)const{return static_cast<const node_t*>(current)->data;}
constexpr pointer operator->(void){return &(static_cast<node_t*>(current)->data);}
constexpr const_pointer operator->(void)const{return &(static_cast<const node_t*>(current)->data);}
constexpr list_iterator& operator++(void){
current = current->next;
return *this;
}
constexpr list_iterator operator++(int){
list_iterator copy(*this);
++(*this);
return copy;
}
constexpr list_iterator& operator--(void){
current = current->prev;
return *this;
}
constexpr list_iterator operator--(int){
list_iterator copy(*this);
--(*this);
return copy;
}
constexpr operator const_list_iterator<T>(void)const{
return const_list_iterator<T>{current};
}
list_iterator next(void)const{
return list_iterator{current->next};
}
list_iterator prev(void)const{
return list_iterator{current->prev};
}
list_node_base* nod(void){return current;}
list_node_base* nod(void)const{return current;}
};
template<class T>
struct const_list_iterator{
template<class U, class Alloc>
friend class rexy::list;
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using node_t = list_node<T>;
const list_node_base* current = nullptr;
constexpr bool operator==(const const_list_iterator& other)const noexcept{return current == other.current;}
constexpr bool operator!=(const const_list_iterator& other)const noexcept{return current != other.current;}
constexpr bool operator==(const list_iterator<T>& other)const noexcept{return current == other.nod();}
constexpr bool operator!=(const list_iterator<T>& other)const noexcept{return current != other.nod();}
constexpr const_reference operator*(void){return static_cast<const node_t*>(current)->data;}
constexpr const_reference operator*(void)const{return static_cast<const node_t*>(current)->data;}
constexpr const_pointer operator->(void){return &(static_cast<const node_t*>(current)->data);}
constexpr const_pointer operator->(void)const{return &(static_cast<const node_t*>(current)->data);}
constexpr const_list_iterator& operator++(void){
current = current->next;
return *this;
}
constexpr const_list_iterator operator++(int){
const_list_iterator copy(*this);
++(*this);
return copy;
}
constexpr const_list_iterator& operator--(void){
current = current->prev;
return *this;
}
constexpr const_list_iterator operator--(int){
const_list_iterator copy(*this);
--(*this);
return copy;
}
const_list_iterator next(void)const{
return const_list_iterator{current->next};
}
const_list_iterator prev(void)const{
return const_list_iterator{current->prev};
}
const list_node_base* nod(void)const{return current;}
protected:
list_iterator<T> unconst(void){
return list_iterator<T>{const_cast<list_node_base*>(current)};
}
};
}
namespace detail{
}
template<class T, class Alloc>
constexpr list<T,Alloc>::list(const allocator_type& alloc)noexcept:
node_allocator_type(alloc){}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(size_type count, const_reference value, const allocator_type& alloc)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>):
node_allocator_type(alloc)
{
constant_initialize_(count, value);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(size_type count, const allocator_type& alloc)noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>):
node_allocator_type(alloc)
{
default_initialize_(count);
}
template<class T, class Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(InputIt first, InputIt last, const allocator_type& alloc)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>):
node_allocator_type(alloc)
{
iterator_initialize_(first, last);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(const list& other, const allocator_type& alloc)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>):
node_allocator_type(alloc)
{
iterator_initialize_(other.begin(), other.end());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(list&& other, const allocator_type& alloc)noexcept:
node_allocator_type(alloc)
{
swap(other);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::list(std::initializer_list<value_type> l, const allocator_type& alloc)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>):
node_allocator_type(alloc)
{
iterator_initialize_(l.begin(), l.end());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
list<T,Alloc>::~list(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
clear();
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::operator=(const list& other)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> list&
{
return (*this = list(other));
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::operator=(list&& other)noexcept -> list&{
swap(other);
return *this;
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::operator=(std::initializer_list<value_type> l)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>) -> list&
{
return (*this = list(l));
}
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator==(const list& other)const noexcept{
if(m_size != other.m_size)
return false;
return std::equal(cbegin(), cend(), other.cbegin());
}
#if __cpp_impl_three_way_comparison
template<class T, class Alloc>
constexpr auto list<T,Alloc>::operator<=>(const list& other)const noexcept{
return std::lexicographical_compare_three_way(cbegin(), cend(), other.cbegin(), other.cend());
}
#else
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator!=(const list& other)const noexcept{
return !(*this == other);
}
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator<(const list& other)const noexcept{
return std::lexicographical_compare(cbegin(), cend(), other.cbegin(), other.cend());
}
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator<=(const list& other)const noexcept{
return !(other < *this);
}
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator>(const list& other)const noexcept{
return other < *this;
}
template<class T, class Alloc>
constexpr bool list<T,Alloc>::operator>=(const list& other)const noexcept{
return !(*this < other);
}
#endif
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::assign(size_type count, const_reference value)noexcept(
std::conditional_t<
std::is_copy_assignable_v<value_type>,
std::is_nothrow_copy_assignable<value_type>,
std::true_type>::value &&
std::is_nothrow_copy_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
assign(sized_constant_iterator{value, count}, sized_constant_iterator<value_type>{{}, 0});
}
template<class T, class Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::assign(InputIt first, InputIt last)noexcept(
std::conditional_t<
std::is_assignable_v<value_type, decltype(*first)>,
std::is_nothrow_assignable<value_type, decltype(*first)>,
std::true_type>::value &&
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
auto current = begin();
size_type i = 0;
if constexpr(std::is_assignable_v<value_type, decltype(*first)>){
for(;i < m_size && first != last;++i){
*current++ = *first++;
}
if(first == last){
erase(current, end());
}
m_size = i;
}else{
clear();
current = end();
}
while(first != last){
current = ++(emplace(current, *first++));
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::assign(std::initializer_list<value_type> l)noexcept(
std::conditional_t<
std::is_assignable_v<value_type, decltype(*l.begin())>,
std::is_nothrow_assignable<value_type, decltype(*l.begin())>,
std::true_type>::value &&
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
assign(l.begin(), l.end());
}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::get_allocator(void)const noexcept -> allocator_type{return {*this};}
//Direct accessors
template<class T, class Alloc>
constexpr auto list<T,Alloc>::front(void)noexcept -> reference{return *begin();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::front(void)const noexcept -> const_reference{return *begin();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::back(void)noexcept -> reference{return *(--end());}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::back(void)const noexcept-> const_reference{return *(--end());}
//Iterators
template<class T, class Alloc>
constexpr auto list<T,Alloc>::begin(void)noexcept -> iterator{return iterator{m_sentinel.next};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::begin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::cbegin(void)const noexcept -> const_iterator{return const_iterator{m_sentinel.next};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::end(void)noexcept -> iterator{return iterator{&m_sentinel};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::end(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::cend(void)const noexcept -> const_iterator{return const_iterator{&m_sentinel};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::next(iterator i)noexcept -> iterator{return i.next();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::next(const_iterator i)noexcept -> const_iterator{return i.next();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::prev(iterator i)noexcept -> iterator{return i.prev();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::prev(const_iterator i)noexcept -> const_iterator{return i.prev();}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::rbegin(void)noexcept -> reverse_iterator{return reverse_iterator{end()};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::rbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::crbegin(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{end()};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::rend(void)noexcept -> reverse_iterator{return reverse_iterator{begin()};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::rend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::crend(void)const noexcept -> const_reverse_iterator{return const_reverse_iterator{begin()};}
//Queries
template<class T, class Alloc>
constexpr bool list<T,Alloc>::empty(void)const noexcept{return m_sentinel.next == nullptr;}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::size(void)const noexcept -> size_type{return m_size;}
template<class T, class Alloc>
constexpr auto list<T,Alloc>::max_size(void)const noexcept -> size_type{return std::numeric_limits<difference_type>::max();}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::clear(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
erase(begin(), end());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::insert(const_iterator pos, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
return insert(pos, value_type{value});
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::insert(const_iterator pos, value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
auto* prev = (--pos).unconst().nod();
auto* next = prev->next;
prev->next = this->allocate(1);
next->prev = prev->next;
std::construct_at(static_cast<node*>(prev->next), next, prev, std::move(value));
++m_size;
return iterator{prev->next};
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::insert(const_iterator pos, size_type count, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
auto start = pos.unconst();
for(auto i = count;i > 0;--i){
pos = ++(insert(pos, value_type{value}));
}
return start;
}
template<class T, class Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::insert(const_iterator pos, InputIt first, InputIt last)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
auto start = pos.unconst();
while(first != last){
pos = ++(insert(pos, *first++));
}
return start;
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::insert(const_iterator pos, std::initializer_list<value_type> l)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*l.begin())> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
return insert(pos, l.begin(), l.end());
}
template<class T, class Alloc>
template<class... Args>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::emplace(const_iterator pos, Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
auto* prev = (--pos).unconst().nod();
auto* next = prev->next;
prev->next = this->allocate(1);
next->prev = prev->next;
std::construct_at(static_cast<node*>(prev->next), next, prev, std::forward<Args>(args)...);
++m_size;
return iterator{prev->next};
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::erase(const_iterator pos)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
auto* n = pos.unconst().nod();
auto* next = n->next;
remove_node_(n);
std::destroy_at(static_cast<node*>(n));
this->deallocate(static_cast<node*>(n), 1);
--m_size;
return iterator{next};
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::erase(const_iterator first, const_iterator last)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> iterator
{
while(first != last){
first = erase(first);
}
return last.unconst();
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::push_back(const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return *insert(cend(), value);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::push_back(value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return *insert(cend(), std::move(value));
}
template<class T, class Alloc>
template<class... Args>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::emplace_back(Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return *emplace(cend(), std::forward<Args>(args)...);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::pop_back(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
erase(--cend());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::push_front(const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return insert(cbegin(), value);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::push_front(value_type&& value)noexcept(
std::is_nothrow_move_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return insert(cbegin(), std::move(value));
}
template<class T, class Alloc>
template<class... Args>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::emplace_front(Args&&... args)noexcept(
std::is_nothrow_constructible_v<value_type, Args&&...> &&
is_nothrow_allocator_v<node_allocator_type>) -> reference
{
return emplace(cbegin(), std::forward<Args>(args)...);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::pop_front(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
erase(cbegin());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::resize(size_type count)noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
resize(count, value_type{});
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::resize(size_type count, value_type value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
while(count > m_size){
insert(cend(), value);
}
while(m_size > count){
erase(--cend());
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::swap(list& other)noexcept{
std::swap(m_sentinel, other.m_sentinel);
std::swap(m_size, other.m_size);
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::merge(list&& other)noexcept{
merge(std::move(other), [](const_reference a, const_reference b){return a < b;});
}
template<class T, class Alloc>
template<class Comp>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::merge(list&& other, Comp comp)noexcept{
if(&other == this){
return;
}
auto it = begin();
auto oit = other.begin();
while(it != end() && oit != other.end()){
if(comp(*oit, *it)){
oit = iterator{get_next_then_move_node_(it.prev().nod(), oit.nod())};
++m_size;
}else{
++it;
}
}
splice(it, std::move(other));
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::splice(const_iterator pos, list&& other)noexcept{
splice(pos, std::move(other), other.begin(), other.end());
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::splice(const_iterator pos, list&& other, const_iterator it)noexcept{
auto oit = it.unconst();
auto prev = (--pos).unconst();
remove_node_(oit.nod());
insert_node_(prev.nod(), oit.nod());
++m_size;
--other.m_size;
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::splice(const_iterator pos, list&& other, const_iterator first, const_iterator last)noexcept{
for(auto oit = first;oit != last;){
auto onext = oit.next();
splice(pos, std::move(other), oit);
oit = onext;
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::remove(const_reference value)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> size_type
{
return remove_if(
[&value](const_reference r) -> bool{
return r == value;
}
);
}
template<class T, class Alloc>
template<class UnaryPred>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::remove_if(UnaryPred pred)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> size_type
{
size_type count = 0;
for(auto it = begin();it != end();){
if(pred(*it)){
it = erase(it);
++count;
}else{
++it;
}
}
return count;
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::reverse(void)noexcept{
auto* it = begin().nod();
std::swap(m_sentinel.next, m_sentinel.prev);
for(;it != &m_sentinel;it = it->prev){
std::swap(it->next, it->prev);
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::unique(void)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> size_type
{
return unique(
[](const_reference first, const_reference second) -> bool{
return first == second;
}
);
}
template<class T, class Alloc>
template<class BinaryPred>
REXY_CPP20_CONSTEXPR
auto list<T,Alloc>::unique(BinaryPred pred)noexcept(
std::is_nothrow_destructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>) -> size_type
{
size_type count = 0;
for(auto it = begin();it != end();++it){
auto next = it.next();
while(next != end() && pred(*it, *next)){
next = erase(next);
++count;
}
}
return count;
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::sort(void)noexcept{
mergesort(begin(), m_size, [](const_reference first, const_reference second)->bool{
return first < second;
});
}
template<class T, class Alloc>
template<class Comp>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::sort(Comp comp)noexcept{
mergesort(begin(), m_size, comp);
}
template<class T, class Alloc>
template<class InputIt>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::iterator_initialize_(InputIt first, InputIt last)noexcept(
std::is_nothrow_constructible_v<value_type, decltype(*first)> &&
is_nothrow_allocator_v<node_allocator_type>)
{
for(;first != last;++first){
emplace_back(*first);
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::constant_initialize_(size_type count, const_reference value)noexcept(
std::is_nothrow_copy_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
for(;count > 0;--count){
emplace_back(value);
}
}
template<class T, class Alloc>
REXY_CPP20_CONSTEXPR
void list<T,Alloc>::default_initialize_(size_type count)noexcept(
std::is_nothrow_default_constructible_v<value_type> &&
is_nothrow_allocator_v<node_allocator_type>)
{
for(;count > 0;--count){
emplace_back();
}
}
template<class T, class Alloc>
template<class Comp>
auto list<T,Alloc>::mergesort(iterator first, size_type firstlen, Comp comp)noexcept -> iterator{
if(firstlen == 1)
return first;
auto [second, secondlen] = ms_split(first, firstlen);
firstlen -= secondlen;
first = mergesort(first, firstlen, comp);
second = mergesort(second, secondlen, comp);
iterator result = first;
//do this outside the loop to save return value
if(comp(*second, *first)){
result = second;
second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
--secondlen;
}
while(firstlen > 0 && secondlen > 0){
if(comp(*second, *first)){
second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
--secondlen;
}else{
++first;
--firstlen;
}
}
//finish off the second list if it isn't already done
while(secondlen > 0){
second = iterator{get_next_then_move_node_(first.prev().nod(), second.nod())};
--secondlen;
}
return result;
}
template<class T, class Alloc>
auto list<T,Alloc>::ms_split(iterator it, size_type len)noexcept -> std::pair<iterator,size_type>{
size_type second_half_len = len / 2;
size_type dist = len - second_half_len;
for(auto i = dist;i > 0;--i){
++it;
}
return {it, second_half_len};
}
template<class T, class Alloc>
void list<T,Alloc>::insert_node_(detail::list_node_base* prev, detail::list_node_base* n)noexcept{
n->next = prev->next;
n->prev = prev;
prev->next->prev = n;
prev->next = n;
}
template<class T, class Alloc>
void list<T,Alloc>::remove_node_(detail::list_node_base* rm)noexcept{
rm->prev->next = rm->next;
rm->next->prev = rm->prev;
}
template<class T, class Alloc>
detail::list_node_base* list<T,Alloc>::get_next_then_move_node_(detail::list_node_base* dest, detail::list_node_base* n)noexcept{
auto* next = n->next;
remove_node_(n);
insert_node_(dest, n);
return next;
}
}
#endif

View File

@ -20,11 +20,10 @@
#define REXY_MPMC_QUEUE_HPP #define REXY_MPMC_QUEUE_HPP
#include <vector> //vector (duh) #include <vector> //vector (duh)
#include <cstddef> //size_t #include <cstdlib> //size_t
#include <atomic> //atomic (duh) #include <atomic> //atomic (duh)
#include "rexy.hpp" #include "rexy.hpp"
#include "utility.hpp" //min
#ifdef __cpp_lib_hardware_interference_size #ifdef __cpp_lib_hardware_interference_size
#include <new> //hardware_destructive_interference_size #include <new> //hardware_destructive_interference_size
@ -43,7 +42,7 @@ namespace rexy{
{ {
public: public:
using value_type = T; using value_type = T;
using size_type = std::size_t; using size_type = size_t;
using pointer = value_type*; using pointer = value_type*;
using const_pointer = const value_type*; using const_pointer = const value_type*;
using reference = value_type&; using reference = value_type&;
@ -54,14 +53,14 @@ namespace rexy{
#if defined(__cpp_lib_hardware_interference_size) #if defined(__cpp_lib_hardware_interference_size)
//libc++ bug //libc++ bug
// https://bugs.llvm.org/show_bug.cgi?id=41423 // https://bugs.llvm.org/show_bug.cgi?id=41423
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 12000 #if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 11000
static constexpr std::size_t cacheline_size = std::hardware_destructive_interference_size; static constexpr size_t cacheline_size = std::hardware_destructive_interference_size;
#else #else
static constexpr std::size_t cacheline_size = 64; static constexpr size_t cacheline_size = 64;
#endif #endif
#else #else
//Best guess //Best guess
static constexpr std::size_t cacheline_size = 64; static constexpr size_t cacheline_size = 64;
#endif #endif
class slot class slot
@ -73,7 +72,7 @@ namespace rexy{
alignas(cacheline_size) std::atomic<size_type> m_turn = {0}; alignas(cacheline_size) std::atomic<size_type> m_turn = {0};
alignas(alignof(value_type)) unsigned char m_data[sizeof(value_type)] = {}; alignas(alignof(value_type)) unsigned char m_data[sizeof(value_type)] = {};
//ensure no false sharing with following data //ensure no false sharing with following data
char cachline_padding[cacheline_size - ((sizeof(m_data) + sizeof(m_turn)) % cacheline_size)]; char cachline_padding[cacheline_size - (sizeof(m_data) + sizeof(m_turn))];
public: public:
slot() = default; slot() = default;
slot(const slot& s); slot(const slot& s);
@ -122,8 +121,6 @@ namespace rexy{
void pop(reference t); void pop(reference t);
bool try_pop(reference t); bool try_pop(reference t);
size_type size(void)const;
private: private:
constexpr size_type rotation_cnt(size_type t); constexpr size_type rotation_cnt(size_type t);
}; };

View File

@ -21,20 +21,20 @@
#include <utility> //forward, move #include <utility> //forward, move
#include <atomic> //memory_order, atomic #include <atomic> //memory_order, atomic
#include "utility.hpp" //memcpy #include <cstring> //memcpy
namespace rexy{ namespace rexy{
template<class T> template<class T>
mpmc_queue<T>::slot::slot(const slot& s): mpmc_queue<T>::slot::slot(const slot& s):
m_turn(s.m_turn.load(std::memory_order_acquire)) m_turn(s.m_turn.load(std::memory_order_acquire))
{ {
rexy::memcpy(m_data, s.m_data, sizeof(s.m_data)); memcpy(m_data, s.m_data, sizeof(s.m_data));
} }
template<class T> template<class T>
mpmc_queue<T>::slot::slot(slot&& s): mpmc_queue<T>::slot::slot(slot&& s):
m_turn(s.m_turn.load(std::memory_order_acquire)) m_turn(s.m_turn.load(std::memory_order_acquire))
{ {
rexy::memcpy(m_data, s.m_data, sizeof(s.m_data)); memcpy(m_data, s.m_data, sizeof(s.m_data));
} }
template<class T> template<class T>
mpmc_queue<T>::slot::~slot(){ mpmc_queue<T>::slot::~slot(){
@ -128,13 +128,12 @@ namespace rexy{
void mpmc_queue<T>::emplace(Args&&... args){ void mpmc_queue<T>::emplace(Args&&... args){
const size_type head = m_head.fetch_add(1, std::memory_order_seq_cst); const size_type head = m_head.fetch_add(1, std::memory_order_seq_cst);
slot& s = m_slots[head % m_slots.capacity()]; slot& s = m_slots[head % m_slots.capacity()];
const size_type rot_count = rotation_cnt(head);
//lsb is in-use flag. wait for it to be 0 //lsb is in-use flag. wait for it to be 0
while(rot_count << 1 != s.turn().load(std::memory_order_acquire)); while(rotation_cnt(head) << 1 != s.turn().load(std::memory_order_acquire));
s.construct(std::forward<Args>(args)...); s.construct(std::forward<Args>(args)...);
//set in-use flag //set in-use flag
s.turn().store((rot_count << 1) + 1, std::memory_order_release); s.turn().store((rotation_cnt(head) << 1) + 1, std::memory_order_release);
} }
template<class T> template<class T>
template<class... Args> template<class... Args>
@ -209,10 +208,6 @@ namespace rexy{
} }
} }
template<class T> template<class T>
auto mpmc_queue<T>::size(void)const -> size_type{
return m_slots.size();
}
template<class T>
constexpr auto mpmc_queue<T>::rotation_cnt(size_type t) -> size_type{ constexpr auto mpmc_queue<T>::rotation_cnt(size_type t) -> size_type{
return (t / m_slots.capacity()); return (t / m_slots.capacity());
} }

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2021-2022 rexy712 Copyright (C) 2021 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,20 +16,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_CONFIG_REXY_HPP #ifndef REXY_REXY_HPP
#define REXY_CONFIG_REXY_HPP #define REXY_REXY_HPP
#define LIBREXY_BUILD_HEADER_ONLY @librexy_HEADER_ONLY_BUILD@
#if LIBREXY_BUILD_HEADER_ONLY
#define LIBREXY_HEADER_ONLY 1
#endif
#define LIBREXY_VERSION @librexy_VERSION_STRING@ #define LIBREXY_VERSION @librexy_VERSION_STRING@
#define LIBREXY_VERSION_MAJOR @librexy_VERSION_MAJOR@
#define LIBREXY_VERSION_MINOR @librexy_VERSION_MINOR@
#define LIBREXY_VERSION_REVISION @librexy_VERSION_REVISION@
#define LIBREXY_ENABLE_SSO @librexy_ENABLE_SSO@
#endif #endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,17 +16,17 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_COMPAT_CPP17_TRAITS_HPP #ifndef REXY_STATIC_STRING_HASH_HPP
#define REXY_COMPAT_CPP17_TRAITS_HPP #define REXY_STATIC_STRING_HASH_HPP
#include <type_traits> //remove_cvref #include "string_hash.hpp"
#include "string_base.hpp"
#include "rexy.hpp"
namespace rexy{ namespace rexy{
template<class T> template<class Char>
struct remove_cvref : public std::remove_cvref<T>{}; struct hash<rexy::static_string<Char>> : public string_hash<rexy::static_string<Char>>{};
template<class T>
using remove_cvref_t = typename remove_cvref<T>::type;
} }

View File

@ -34,7 +34,7 @@ namespace rexy{
public: public:
template<class U> template<class U>
constexpr explicit steal(U&& u) constexpr steal(U&& u)
noexcept(std::is_nothrow_constructible<T,U&&>::value): noexcept(std::is_nothrow_constructible<T,U&&>::value):
m_val(std::forward<U>(u)){} m_val(std::forward<U>(u)){}

View File

@ -1,97 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_STORAGE_FOR_HPP
#define REXY_STORAGE_FOR_HPP
#include <utility> //forward, move
#include <type_traits> //is_nothrow_constructible, etc
#include "compat/standard.hpp"
namespace rexy{
//A wrapper around raw storage.
//Allows default constructing objects with members which cannot be default constructed
template<class T>
class storage_for
{
public:
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using rvalue_reference = T&&;
static constexpr auto align = alignof(value_type);
static constexpr auto size = sizeof(value_type);
private:
#if __cplusplus >= 202002L && __has_cpp_attribute(no_unique_address) && __cpp_constexpr >= 202002L
union storage_{
[[no_unique_address]]
struct empty_{}empty = {};
T data;
}m_storage;
#else //__cplusplus
alignas(align) unsigned char m_storage[size];
#endif //__cplusplus
unsigned char m_dirty:1 = 0;
public:
constexpr storage_for(void) = default;
template<class... Args>
constexpr storage_for(Args&&... args)noexcept(std::is_nothrow_constructible<value_type,Args...>::value);
constexpr storage_for(const_reference t)noexcept(std::is_nothrow_copy_constructible<value_type>::value);
constexpr storage_for(rvalue_reference t)noexcept(std::is_nothrow_move_constructible<value_type>::value);
constexpr storage_for(const storage_for& s)noexcept(std::is_nothrow_copy_constructible<value_type>::value);
constexpr storage_for(storage_for&& s)noexcept(std::is_nothrow_move_constructible<value_type>::value);
REXY_CPP20_CONSTEXPR ~storage_for(void)noexcept(std::is_nothrow_destructible<value_type>::value);
constexpr storage_for& operator=(const storage_for& s)noexcept(std::is_nothrow_copy_assignable<value_type>::value);
constexpr storage_for& operator=(storage_for&& s)noexcept(std::is_nothrow_move_assignable<value_type>::value);
constexpr storage_for& operator=(const_reference t)noexcept(std::is_nothrow_copy_assignable<value_type>::value);
constexpr storage_for& operator=(rvalue_reference t)noexcept(std::is_nothrow_move_assignable<value_type>::value);
constexpr void destroy(void)noexcept(std::is_nothrow_destructible<value_type>::value);
constexpr operator reference(void)noexcept;
constexpr operator const_reference(void)const noexcept;
constexpr operator rvalue_reference(void)&& noexcept;
constexpr reference get(void)noexcept;
constexpr const_reference get(void)const noexcept;
constexpr pointer operator->(void)noexcept;
constexpr const_pointer operator->(void)const noexcept;
constexpr reference operator*(void)noexcept;
constexpr const_reference operator*(void)const noexcept;
constexpr bool valid(void)const;
};
}
#include "storage_for.tpp"
#endif

View File

@ -1,269 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_STORAGE_FOR_TPP
#define REXY_STORAGE_FOR_TPP
#include <utility> //forward, move
#if __cplusplus >= 202002L && __has_cpp_attribute(no_unique_address) && __cpp_constexpr >= 202002L
#include <memory> //construct_at, destroy_at
namespace rexy{
template<class T>
template<class... Args>
constexpr storage_for<T>::storage_for(Args&&... args)noexcept(std::is_nothrow_constructible<value_type,Args...>::value){
std::construct_at(&m_storage.data, std::forward<Args>(args)...);
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(const_reference t)noexcept(std::is_nothrow_copy_constructible<value_type>::value){
std::construct_at(&m_storage.data, t);
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(rvalue_reference t)noexcept(std::is_nothrow_move_constructible<value_type>::value){
std::construct_at(&m_storage.data, std::move(t));
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(const storage_for& s)noexcept(std::is_nothrow_copy_constructible<value_type>::value){
if(s.m_dirty){
std::construct_at(&m_storage.data, s.m_storage.data);
m_dirty = 1;
}
}
template<class T>
constexpr storage_for<T>::storage_for(storage_for&& s)noexcept(std::is_nothrow_move_constructible<value_type>::value){
if(s.m_dirty){
std::construct_at(&m_storage.data, std::move(s.m_storage.data));
m_dirty = 1;
}
}
template<class T>
REXY_CPP20_CONSTEXPR storage_for<T>::~storage_for(void)noexcept(std::is_nothrow_destructible<value_type>::value){
if(m_dirty){
destroy();
}
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(const storage_for& s)noexcept(std::is_nothrow_copy_assignable<value_type>::value){
return ((*this) = storage_for(s));
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(storage_for&& s)noexcept(std::is_nothrow_move_assignable<value_type>::value){
if(s.m_dirty){
return ((*this) = std::move(s.m_storage.data));
}else{
if(m_dirty){
destroy();
}
}
return *this;
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(const_reference t)noexcept(std::is_nothrow_copy_assignable<value_type>::value){
if(m_dirty){
m_storage.data = t;
}else{
std::construct_at(&m_storage.data, t);
}
m_dirty = 1;
return *this;
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(rvalue_reference t)noexcept(std::is_nothrow_move_assignable<value_type>::value){
if(m_dirty){
m_storage.data = std::move(t);
}else{
std::construct_at(&m_storage.data, std::move(t));
}
m_dirty = 1;
return *this;
}
template<class T>
constexpr void storage_for<T>::destroy(void)noexcept(std::is_nothrow_destructible<value_type>::value){
if(m_dirty){
std::destroy_at(&m_storage.data);
m_dirty = 0;
}
}
template<class T>
constexpr storage_for<T>::operator reference(void)noexcept{
return m_storage.data;
}
template<class T>
constexpr storage_for<T>::operator const_reference(void)const noexcept{
return m_storage.data;
}
template<class T>
constexpr storage_for<T>::operator rvalue_reference(void)&& noexcept{
return std::move(m_storage.data);
}
template<class T>
constexpr auto storage_for<T>::get(void)noexcept -> reference{
return m_storage.data;
}
template<class T>
constexpr auto storage_for<T>::get(void)const noexcept -> const_reference{
return m_storage.data;
}
template<class T>
constexpr auto storage_for<T>::operator->(void)noexcept -> pointer{
return &m_storage.data;
}
template<class T>
constexpr auto storage_for<T>::operator->(void)const noexcept -> const_pointer{
return &m_storage.data;
}
template<class T>
constexpr auto storage_for<T>::operator*(void)noexcept -> reference{
return m_storage.data;
}
template<class T>
constexpr auto storage_for<T>::operator*(void)const noexcept -> const_reference{
return m_storage.data;
}
template<class T>
constexpr bool storage_for<T>::valid(void)const{
return m_dirty;
}
}
#else //__cplusplus
namespace rexy{
template<class T>
template<class... Args>
constexpr storage_for<T>::storage_for(Args&&... args)noexcept(std::is_nothrow_constructible<value_type,Args...>::value){
new (m_storage) T(std::forward<Args>(args)...);
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(const_reference t)noexcept(std::is_nothrow_copy_constructible<value_type>::value){
new (m_storage) T(t);
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(rvalue_reference t)noexcept(std::is_nothrow_move_constructible<value_type>::value){
new (m_storage) T(std::move(t));
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(const storage_for& s)noexcept(std::is_nothrow_copy_constructible<value_type>::value){
new (m_storage) T(reinterpret_cast<const T&>(s.m_storage));
m_dirty = 1;
}
template<class T>
constexpr storage_for<T>::storage_for(storage_for&& s)noexcept(std::is_nothrow_move_constructible<value_type>::value){
new (m_storage) T(std::move(reinterpret_cast<T&>(&s.m_storage)));
m_dirty = 1;
}
template<class T>
REXY_CPP20_CONSTEXPR storage_for<T>::~storage_for(void)noexcept(std::is_nothrow_destructible<value_type>::value){
if(m_dirty){
destroy();
}
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(const storage_for& s)noexcept(std::is_nothrow_copy_assignable<value_type>::value){
reinterpret_cast<T&>(m_storage) = static_cast<const T&>(s);
return *this;
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(storage_for&& s)noexcept(std::is_nothrow_move_assignable<value_type>::value){
reinterpret_cast<T&>(m_storage) = static_cast<T&&>(std::move(s));
return *this;
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(const_reference t)noexcept(std::is_nothrow_copy_assignable<value_type>::value){
reinterpret_cast<T&>(m_storage) = t;
return *this;
}
template<class T>
constexpr storage_for<T>& storage_for<T>::operator=(rvalue_reference t)noexcept(std::is_nothrow_move_assignable<value_type>::value){
reinterpret_cast<T&>(m_storage) = std::move(t);
return *this;
}
template<class T>
constexpr void storage_for<T>::destroy(void)noexcept(std::is_nothrow_destructible<value_type>::value){
reinterpret_cast<T*>(&m_storage)->~T();
m_dirty = 0;
}
template<class T>
constexpr storage_for<T>::operator reference(void)noexcept{
return reinterpret_cast<reference>(m_storage);
}
template<class T>
constexpr storage_for<T>::operator const_reference(void)const noexcept{
return reinterpret_cast<const_reference>(m_storage);
}
template<class T>
constexpr storage_for<T>::operator rvalue_reference(void)&& noexcept{
return reinterpret_cast<rvalue_reference>(std::move(m_storage));
}
template<class T>
constexpr auto storage_for<T>::get(void)noexcept -> reference{
return reinterpret_cast<reference>(m_storage);
}
template<class T>
constexpr auto storage_for<T>::get(void)const noexcept -> const_reference{
return reinterpret_cast<const_reference>(m_storage);
}
template<class T>
constexpr auto storage_for<T>::operator->(void)noexcept -> pointer{
return reinterpret_cast<T*>(&m_storage);
}
template<class T>
constexpr auto storage_for<T>::operator->(void)const noexcept -> const_pointer{
return reinterpret_cast<const T*>(&m_storage);
}
template<class T>
constexpr auto storage_for<T>::operator*(void)noexcept -> reference{
return reinterpret_cast<T&>(m_storage);
}
template<class T>
constexpr auto storage_for<T>::operator*(void)const noexcept -> const_reference{
return reinterpret_cast<const T&>(m_storage);
}
template<class T>
constexpr bool storage_for<T>::valid(void)const{
return m_dirty;
}
}
#endif //__cplusplus
#endif

View File

@ -26,25 +26,17 @@
namespace rexy{ namespace rexy{
//new allocated string //new allocated string
using string = basic_string<char>; using string = basic_string<char,allocator<char>>;
using wstring = basic_string<wchar_t>;
using u16string = basic_string<char16_t>;
using u32string = basic_string<char32_t>;
#ifdef __cpp_char8_t
using u8string = basic_string<char8_t>;
#endif
#ifndef LIBREXY_HEADER_ONLY
extern template class basic_string<char,allocator<char>>; extern template class basic_string<char,allocator<char>>;
extern template class basic_string<wchar_t,allocator<wchar_t>>; extern template class basic_string<wchar_t,allocator<wchar_t>>;
extern template class basic_string<char16_t,allocator<char16_t>>; extern template class basic_string<char16_t,allocator<char16_t>>;
extern template class basic_string<char32_t,allocator<char32_t>>; extern template class basic_string<char32_t,allocator<char32_t>>;
#ifdef __cpp_char8_t
extern template class basic_string<char8_t,allocator<char8_t>>;
#endif
#endif //LIBREXY_HEADER_ONLY
} }
#ifdef REXY_CX_HASH_HPP
#include "cx/basic_string_hash.hpp"
#endif
#endif #endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -21,38 +21,28 @@
#include <type_traits> //is_same, integral_contant, enable_if, etc #include <type_traits> //is_same, integral_contant, enable_if, etc
#include <utility> //forward #include <utility> //forward
#include <cstddef> //std::size_t,ptrdiff #include <cstddef> //size_t,ptrdiff
#include <cstring> //strlen
#include <climits> //CHAR_BIT #include <climits> //CHAR_BIT
#include <iterator> //reverse_iterator #include <iterator> //reverse_iterator
#include <initializer_list>
#include "steal.hpp" #include "steal.hpp"
#include "utility.hpp" //memcpy #include "utility.hpp"
#include "traits.hpp" #include "traits.hpp"
#include "expression.hpp" #include "expression.hpp"
#include "detail/string_appender.hpp" #include "detail/string_appender.hpp"
#include "detail/hasallocator.hpp" #include "detail/hasallocator.hpp"
#include "allocator.hpp"
#include "rexy.hpp" #include "rexy.hpp"
#include "compat/standard.hpp"
namespace rexy{ namespace rexy{
#ifndef LIBREXY_ENABLE_SSO
#define LIBREXY_ENABLE_SSO 1
#endif
template<class Char>
class basic_string_view;
//Base of all RAII strings. Its use is allowing passing of rexy strings to functions without knowing the exact type //Base of all RAII strings. Its use is allowing passing of rexy strings to functions without knowing the exact type
template<class Char> template<class Char>
class string_base class string_base
{ {
public: public:
using value_type = Char; using value_type = Char;
using size_type = std::size_t; using size_type = size_t;
using difference_type = ptrdiff_t; using difference_type = ptrdiff_t;
using pointer = value_type*; using pointer = value_type*;
using const_pointer = const value_type*; using const_pointer = const value_type*;
@ -63,7 +53,6 @@ namespace rexy{
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
#if LIBREXY_ENABLE_SSO != 0
private: private:
static constexpr size_type EXTRA_SDATA_LEN = 0; static constexpr size_type EXTRA_SDATA_LEN = 0;
@ -73,7 +62,7 @@ namespace rexy{
size_type capacity:(CHAR_BIT*sizeof(size_type)-1); //take away last bit from capacity for islong size_type capacity:(CHAR_BIT*sizeof(size_type)-1); //take away last bit from capacity for islong
size_type length; //length of string excluding null terminator size_type length; //length of string excluding null terminator
constexpr ldata(void)noexcept: constexpr ldata(void)noexcept:
islong(1), islong(0),
capacity(0), capacity(0),
length(0){} length(0){}
}; };
@ -81,7 +70,7 @@ namespace rexy{
static constexpr size_type MAX_SHORT_LEN = EXTRA_SDATA_LEN+sizeof(ldata)-2; static constexpr size_type MAX_SHORT_LEN = EXTRA_SDATA_LEN+sizeof(ldata)-2;
//represent short string //represent short string
struct sdata{ struct sdata{
unsigned char islong:1; //common subsequence with long string unsigned char islong:1; //common subsequenci with long string
unsigned char length:(CHAR_BIT-1); //take away last bit from length for islong, excludes null terminator unsigned char length:(CHAR_BIT-1); //take away last bit from length for islong, excludes null terminator
value_type data[MAX_SHORT_LEN+1]; //char array for string storage value_type data[MAX_SHORT_LEN+1]; //char array for string storage
constexpr sdata(void)noexcept: constexpr sdata(void)noexcept:
@ -89,12 +78,12 @@ namespace rexy{
length(0), length(0),
data{}{} data{}{}
}; };
//union of short and long string representations. //union of short and long string representations. Default to long representation for static_string's use case.
union combine_data{ union combine_data{
ldata l; ldata l;
sdata s; sdata s;
constexpr combine_data(void)noexcept: constexpr combine_data(void)noexcept:
s(){} l(){}
}m_data; }m_data;
//direct access to current string data regardless of representation. Increases access speed. //direct access to current string data regardless of representation. Increases access speed.
@ -135,12 +124,6 @@ namespace rexy{
constexpr void set_short_capacity(size_type){} constexpr void set_short_capacity(size_type){}
constexpr size_type get_long_capacity(void)const{return m_data.l.capacity;} constexpr size_type get_long_capacity(void)const{return m_data.l.capacity;}
constexpr size_type get_short_capacity(void)const{return MAX_SHORT_LEN;} constexpr size_type get_short_capacity(void)const{return MAX_SHORT_LEN;}
constexpr void set_capacity(size_type s){
if(islong())
set_long_capacity(s);
else
set_short_capacity(s);
}
constexpr void set_length(size_type s){ constexpr void set_length(size_type s){
if(islong()) if(islong())
set_long_length(s); set_long_length(s);
@ -160,7 +143,8 @@ namespace rexy{
}else if(len){ }else if(len){
set_islong_flag(false); set_islong_flag(false);
pointer raw = set_short_ptr(); pointer raw = set_short_ptr();
rexy::memcpy(raw, data, sizeof(value_type)*len); if(len)
memcpy(raw, data, sizeof(value_type)*len);
raw[len] = 0; raw[len] = 0;
set_short_length(len); set_short_length(len);
set_short_capacity(cap); set_short_capacity(cap);
@ -177,7 +161,8 @@ namespace rexy{
{ {
s.set_islong_flag(false); s.set_islong_flag(false);
} }
REXY_CPP20_CONSTEXPR ~string_base(void)noexcept = default; ~string_base(void)noexcept = default;
constexpr string_base& operator=(string_base&& s)noexcept{ constexpr string_base& operator=(string_base&& s)noexcept{
std::swap(m_data, s.m_data); std::swap(m_data, s.m_data);
if(this->islong()) if(this->islong())
@ -188,7 +173,9 @@ namespace rexy{
} }
return *this; return *this;
} }
public: public:
//Length of string not including null terminator
constexpr size_type length(void)const noexcept{ constexpr size_type length(void)const noexcept{
if(islong()) if(islong())
return get_long_length(); return get_long_length();
@ -201,192 +188,56 @@ namespace rexy{
else else
return get_short_capacity(); return get_short_capacity();
} }
static constexpr bool uses_sso(void){return true;}
static constexpr size_type short_string_size(void){return MAX_SHORT_LEN;}
#else //LIBREXY_ENABLE_SSO
private:
//direct access to current string
pointer m_raw = nullptr;
size_type m_length = 0;
size_type m_capacity = 0;
protected:
constexpr pointer get_pointer(void){return m_raw;}
constexpr const_pointer get_pointer(void)const{return m_raw;}
constexpr void set_length(size_type s){m_length = s;}
constexpr void set_capacity(size_type s){m_capacity = s;}
constexpr bool islong(void)const{return true;}
constexpr pointer set_short_ptr(void){return m_raw;}
constexpr pointer set_long_ptr(pointer ptr){return m_raw = ptr;}
protected:
constexpr string_base(void)noexcept = default;
//Initialize without copying
constexpr string_base(pointer data, size_type len, size_type cap)noexcept:
m_raw(data),
m_length(len),
m_capacity(cap){}
constexpr string_base(pointer data, size_type len)noexcept:
string_base(data, len, len){}
//Copy ctor, copy length+capacity+short string, not long string value
constexpr string_base(const string_base& s)noexcept:
m_raw(s.m_raw),
m_length(s.m_length),
m_capacity(s.m_capacity){}
constexpr string_base(string_base&& s)noexcept:
m_raw(std::exchange(s.m_raw, nullptr)),
m_length(s.m_length),
m_capacity(s.m_capacity){}
REXY_CPP20_CONSTEXPR ~string_base(void)noexcept = default;
constexpr string_base& operator=(string_base&& s)noexcept{
std::swap(m_raw, s.m_raw);
m_length = s.m_length;
m_capacity = s.m_capacity;
return *this;
}
public:
constexpr size_type length(void)const noexcept{
return m_length;
}
constexpr size_type capacity(void)const noexcept{
return m_capacity;
}
static constexpr bool uses_sso(void){return false;}
static constexpr size_type short_string_size(void){return 0;}
#endif //LIBREXY_ENABLE_SSO
public:
//Length of string not including null terminator
constexpr size_type size(void)const noexcept{
return length();
}
constexpr size_type max_size(void)const noexcept{
return size_type{-2};
}
//direct access to managed pointer //direct access to managed pointer
constexpr pointer c_str(void)noexcept{return get_pointer();} constexpr pointer c_str(void)noexcept{return get_pointer();}
constexpr const_pointer c_str(void)const noexcept{return get_pointer();} constexpr const_pointer c_str(void)const noexcept{return get_pointer();}
constexpr pointer data(void)noexcept{return get_pointer();} constexpr pointer get(void)noexcept{return get_pointer();}
constexpr const_pointer data(void)const noexcept{return get_pointer();} constexpr const_pointer get(void)const noexcept{return get_pointer();}
constexpr operator basic_string_view<value_type>(void)const noexcept{return basic_string_view<value_type>(begin(), end());} constexpr operator pointer(void)noexcept{return get_pointer();}
constexpr operator const_pointer(void)const noexcept{return get_pointer();}
//true if m_data is not empty //true if m_data is not empty
constexpr bool valid(void)const noexcept{return length() > 0;} constexpr bool valid(void)const noexcept{return length() > 0;}
constexpr bool empty(void)const noexcept{return length() == 0;}
constexpr reference operator[](size_type i)noexcept{return get_pointer()[i];} constexpr reference operator[](size_type i)noexcept{return get_pointer()[i];}
constexpr const_reference operator[](size_type i)const noexcept{return get_pointer()[i];} constexpr const_reference operator[](size_type i)const noexcept{return get_pointer()[i];}
constexpr reference at(size_type i)noexcept{return get_pointer()[i];}
constexpr const_reference at(size_type i)const noexcept{return get_pointer()[i];}
constexpr const_iterator search(basic_string_view<value_type> sv)const noexcept; constexpr const_iterator search(const string_base& s)const;
constexpr iterator search(basic_string_view<value_type> sv)noexcept; constexpr const_iterator search(const_pointer c)const;
constexpr const_iterator search(const_pointer c)const noexcept; constexpr iterator search(const string_base& s);
constexpr iterator search(const_pointer c)noexcept; constexpr iterator search(const_pointer c);
template<class Searcher> template<class Searcher>
constexpr const_iterator search(const_pointer c, const Searcher& searcher)const noexcept( constexpr const_iterator search(const string_base& s, const Searcher& searcher)const;
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_pointer, const_pointer>);
template<class Searcher> template<class Searcher>
constexpr iterator search(const_pointer c, const Searcher& searcher)noexcept( constexpr const_iterator search(const_pointer c, const Searcher& searcher)const;
std::is_nothrow_invocable_v<Searcher, iterator, iterator, const_pointer, const_pointer>);
constexpr const_iterator rsearch(basic_string_view<value_type> sv)const noexcept;
constexpr iterator rsearch(basic_string_view<value_type> sv)noexcept;
constexpr const_iterator rsearch(const_pointer c)const noexcept;
constexpr iterator rsearch(const_pointer c)noexcept;
template<class Searcher> template<class Searcher>
constexpr const_iterator rsearch(const_pointer c, const Searcher& searcher)const noexcept( constexpr iterator search(const string_base& s, const Searcher& searcher);
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_pointer, const_pointer>);
template<class Searcher> template<class Searcher>
constexpr iterator rsearch(const_pointer c, const Searcher& searcher)noexcept( constexpr iterator search(const_pointer c, const Searcher& searcher);
std::is_nothrow_invocable_v<Searcher, iterator, iterator, const_pointer, const_pointer>); constexpr bool compare(const string_base& s)const{return *this == s;}
constexpr bool compare(const_pointer c)const{return *this == c;}
constexpr bool starts_with(basic_string_view<value_type> sv)const noexcept; constexpr iterator begin(void){return get_pointer();}
constexpr bool starts_with(value_type v)const noexcept; constexpr const_iterator begin(void)const{return get_pointer();}
constexpr bool starts_with(const_pointer str)const noexcept; constexpr iterator end(void){return get_pointer()+length();}
constexpr const_iterator end(void)const{return get_pointer()+length();}
constexpr const_iterator cbegin(void)const{return begin();}
constexpr const_iterator cend(void)const{return end();}
constexpr bool ends_with(basic_string_view<value_type> sv)const noexcept; constexpr reverse_iterator rbegin(void){return reverse_iterator(get_pointer()+length());}
constexpr bool ends_with(value_type v)const noexcept; constexpr const_reverse_iterator rbegin(void)const{return const_reverse_iterator(get_pointer()+length());}
constexpr bool ends_with(const_pointer str)const noexcept; constexpr reverse_iterator rend(void){return reverse_iterator(get_pointer()-1);}
constexpr const_reverse_iterator rend(void)const{return const_reverse_iterator(get_pointer()-1);}
constexpr const_reverse_iterator crbegin(void)const{return rbegin();}
constexpr const_reverse_iterator crend(void)const{return rend();}
constexpr bool contains(basic_string_view<value_type> sv)const noexcept; static constexpr bool uses_sso(void){return true;}
constexpr bool contains(value_type v)const noexcept; static constexpr size_type short_string_size(void){return MAX_SHORT_LEN;}
constexpr bool contains(const_pointer str)const noexcept; };
//TODO more compares
constexpr bool compare(const string_base& s)const noexcept{return *this == s;}
constexpr bool compare(basic_string_view<value_type> s)const noexcept{return *this == s;}
constexpr bool compare(const_pointer c)const noexcept{return *this == c;}
constexpr size_type find_first_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_first_of(const_pointer c, size_type start = 0)const noexcept;
constexpr size_type find_first_of(const_pointer c, size_type start, size_type size)const noexcept;
template<class StringView>
constexpr auto find_first_of(const StringView& str, size_type start = 0)const noexcept(
std::is_nothrow_convertible_v<const StringView&,basic_string_view<value_type>>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>>,
size_type>;
constexpr size_type find_last_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_last_of(const_pointer c, size_type start = 0)const noexcept;
constexpr size_type find_last_of(const_pointer c, size_type start, size_type size)const noexcept;
template<class StringView>
constexpr auto find_last_of(const StringView& str, size_type start = 0)const noexcept(
std::is_nothrow_convertible_v<const StringView&,basic_string_view<value_type>>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>>,
size_type>;
constexpr size_type find_first_not_of(const_pointer str, size_type start, size_type count)const noexcept;
constexpr size_type find_first_not_of(const_pointer str, size_type start = 0)const noexcept;
constexpr size_type find_first_not_of(value_type v, size_type start = 0)const noexcept;
template<class StringView>
constexpr auto find_first_not_of(const StringView& str, size_type start = 0)const noexcept(
std::is_nothrow_convertible_v<const StringView&,basic_string_view<value_type>>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>>,
size_type>;
constexpr size_type find_last_not_of(const_pointer str, size_type start, size_type count)const noexcept;
constexpr size_type find_last_not_of(const_pointer str, size_type start = 0)const noexcept;
constexpr size_type find_last_not_of(value_type v, size_type start = 0)const noexcept;
template<class StringView>
constexpr auto find_last_not_of(const StringView& str, size_type start = 0)const noexcept(
std::is_nothrow_convertible_v<const StringView&,basic_string_view<value_type>>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>>,
size_type>;
constexpr reference front(void)noexcept{return *get_pointer();}
constexpr const_reference front(void)const noexcept{return *get_pointer();}
constexpr reference back(void)noexcept{return *(get_pointer() + length() - 1);}
constexpr const_reference back(void)const noexcept{return *(get_pointer() + length() - 1);}
constexpr iterator begin(void)noexcept{return get_pointer();}
constexpr const_iterator begin(void)const noexcept{return get_pointer();}
constexpr iterator end(void)noexcept{return get_pointer()+length();}
constexpr const_iterator end(void)const noexcept{return get_pointer()+length();}
constexpr const_iterator cbegin(void)const noexcept{return begin();}
constexpr const_iterator cend(void)const noexcept{return end();}
constexpr reverse_iterator rbegin(void)noexcept{return reverse_iterator(get_pointer()+length());}
constexpr const_reverse_iterator rbegin(void)const noexcept{return const_reverse_iterator(get_pointer()+length());}
constexpr reverse_iterator rend(void)noexcept{return reverse_iterator(get_pointer());}
constexpr const_reverse_iterator rend(void)const noexcept{return const_reverse_iterator(get_pointer());}
constexpr const_reverse_iterator crbegin(void)const noexcept{return rbegin();}
constexpr const_reverse_iterator crend(void)const noexcept{return rend();}
constexpr void clear(void)noexcept;
constexpr basic_string_view<value_type> create_view(void)const noexcept;
constexpr basic_string_view<value_type> create_view(const_iterator start, const_iterator fin)const noexcept;
}; //class string_base
//Supplies all functions that string_base can't implement //Supplies all functions that string_base can't implement
template<class Char, REXY_ALLOCATOR_CONCEPT Alloc = rexy::allocator<Char>> template<class Char, class Allocator>
class basic_string : protected detail::hasallocator<Alloc>, public string_base<Char> class basic_string : protected detail::hasallocator<Allocator>, public string_base<Char>
{ {
public: public:
using value_type = typename string_base<Char>::value_type; using value_type = typename string_base<Char>::value_type;
@ -400,284 +251,68 @@ namespace rexy{
using const_iterator = typename string_base<Char>::const_iterator; using const_iterator = typename string_base<Char>::const_iterator;
using reverse_iterator = typename string_base<Char>::reverse_iterator; using reverse_iterator = typename string_base<Char>::reverse_iterator;
using const_reverse_iterator = typename string_base<Char>::const_reverse_iterator; using const_reverse_iterator = typename string_base<Char>::const_reverse_iterator;
using allocator_type = Alloc; using allocator_type = Allocator;
static constexpr size_type npos = size_type(-1);
private: private:
void _copy_construct_string(const_pointer data, size_type len, size_type cap)
REXY_CPP20_CONSTEXPR noexcept(noexcept(this->allocate(0)));
void _copy_construct_string(const_pointer data, size_type len, size_type cap)noexcept( basic_string& _copy_string(const_pointer s, size_type len)
is_nothrow_allocator_v<Alloc>); noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
REXY_CPP20_CONSTEXPR
basic_string& _copy_string(const_pointer s, size_type len)noexcept(
is_nothrow_allocator_v<Alloc>);
template<class InputIt>
REXY_CPP20_CONSTEXPR
basic_string& _insert_impl(size_type pos, InputIt start, size_type insert_count)noexcept(
is_nothrow_allocator_v<Alloc>);
template<class InputIt>
constexpr basic_string& _replace_impl(size_type pos, size_type count, InputIt src, size_type count2)noexcept;
public: public:
constexpr basic_string(void)noexcept; constexpr basic_string(void)noexcept;
constexpr basic_string(rexy::steal<pointer> data, size_type len)noexcept; constexpr basic_string(rexy::steal<pointer> data, size_type len)noexcept;
constexpr basic_string(rexy::steal<pointer> data, size_type len, size_type cap)noexcept; constexpr basic_string(rexy::steal<pointer> data, size_type len, size_type cap)noexcept;
constexpr basic_string(rexy::steal<pointer> data)noexcept; constexpr basic_string(rexy::steal<pointer> data)noexcept;
basic_string(const_pointer data, size_type len)noexcept(noexcept(this->allocate(0)));
REXY_CPP20_CONSTEXPR basic_string(const_pointer data, size_type len, size_type cap)noexcept(noexcept(this->allocate(0)));
basic_string(const_pointer data, size_type len)noexcept( basic_string(const_pointer data)noexcept(noexcept(this->allocate(0)));
is_nothrow_allocator_v<Alloc>); explicit basic_string(size_type len)noexcept(noexcept(this->allocate(0)));
basic_string(size_type len, size_type cap)noexcept(noexcept(this->allocate(0)));
REXY_CPP20_CONSTEXPR
basic_string(const_pointer data, size_type len, size_type cap)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string(const_pointer data)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
explicit basic_string(size_type len)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string(size_type len, size_type cap)noexcept(
is_nothrow_allocator_v<Alloc>);
template<class InputIt, class Enable = std::enable_if_t<is_legacy_input_iterator_v<InputIt>,int>>
REXY_CPP20_CONSTEXPR
basic_string(InputIt start, InputIt fin)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string(const basic_string_view<Char>& sv)noexcept(
is_nothrow_allocator_v<Alloc>);
//normal copy and move ctors //normal copy and move ctors
REXY_CPP20_CONSTEXPR basic_string(const basic_string& b)noexcept(noexcept(this->allocate(0)));
basic_string(const basic_string& b)noexcept(
is_nothrow_allocator_v<Alloc>);
constexpr basic_string(basic_string&& s)noexcept; constexpr basic_string(basic_string&& s)noexcept;
basic_string(const string_base<Char>&)noexcept(noexcept(this->allocate(0)));
REXY_CPP20_CONSTEXPR
basic_string(const string_base<Char>&)noexcept(
is_nothrow_allocator_v<Alloc>);
//dtor //dtor
REXY_CPP20_CONSTEXPR ~basic_string(void)noexcept(noexcept(this->deallocate(nullptr, 0)));
~basic_string(void)noexcept(
is_nothrow_allocator_v<Alloc>);
basic_string& operator=(const basic_string& s)
REXY_CPP20_CONSTEXPR noexcept(noexcept(this->allocate(0)) &&
basic_string& operator=(const basic_string& s)noexcept( noexcept(this->deallocate(nullptr,0)));
is_nothrow_allocator_v<Alloc>);
constexpr basic_string& operator=(basic_string&& s)noexcept; constexpr basic_string& operator=(basic_string&& s)noexcept;
REXY_CPP20_CONSTEXPR basic_string& operator=(const string_base<Char>& s)
basic_string& operator=(const string_base<Char>& s)noexcept( noexcept(noexcept(this->allocate(0)) &&
is_nothrow_allocator_v<Alloc>); noexcept(this->deallocate(nullptr,0)));
REXY_CPP20_CONSTEXPR
basic_string& operator=(const basic_string_view<Char>& sv)noexcept(
is_nothrow_allocator_v<Alloc>);
//Copy from c string //Copy from c string
REXY_CPP20_CONSTEXPR basic_string& operator=(const_pointer c)
basic_string& operator=(const_pointer c)noexcept( noexcept(noexcept(this->allocate(0)) &&
is_nothrow_allocator_v<Alloc>); noexcept(this->deallocate(nullptr,0)));
//These can't be put in base because they require us to know the type of Alloc
constexpr size_type find_first_of(const basic_string& str, size_type start = 0)const noexcept;
constexpr size_type find_last_of(const basic_string& str, size_type start = 0)const noexcept;
constexpr size_type find_first_not_of(const basic_string& str, size_type start = 0)const noexcept;
constexpr size_type find_last_not_of(const basic_string& str, size_type start = 0)const noexcept;
//Replace managed pointer. Frees existing value //Replace managed pointer. Frees existing value
REXY_CPP20_CONSTEXPR void reset(pointer val = nullptr)noexcept(noexcept(this->deallocate(nullptr,0)));
void reset(pointer val = nullptr)noexcept( void reset(pointer val, size_type len)noexcept(noexcept(this->deallocate(nullptr,0)));
is_nothrow_allocator_v<Alloc>); bool resize(size_type newsize)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
REXY_CPP20_CONSTEXPR void append(const_pointer data, size_type len)
void reset(pointer val, size_type len)noexcept( noexcept(noexcept(this->allocate(0)) &&
is_nothrow_allocator_v<Alloc>); noexcept(this->deallocate(nullptr,0)));
void append(const_pointer data)
noexcept(noexcept(this->allocate(0)) &&
noexcept(this->deallocate(nullptr,0)));
REXY_CPP20_CONSTEXPR template<class Alloc = allocator_type>
bool reserve(size_type newsize)noexcept( basic_string<value_type,Alloc> substring(size_type start, size_type end)const;
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR pointer release(void)noexcept(noexcept(this->allocate(0)));
void shrink_to_fit(void)noexcept( using detail::hasallocator<Allocator>::allocator;
is_nothrow_allocator_v<Alloc>); };
REXY_CPP20_CONSTEXPR
void resize(size_type newsize, value_type v = value_type())noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, size_type insert_count, value_type v)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, value_type v)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, const_pointer str)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, const_pointer str, size_type insert_count)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, const basic_string& other)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(size_type pos, const basic_string& other, size_type index_str, size_type count = npos)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(const_iterator pos, value_type v)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& insert(const_iterator pos, size_type count, value_type v)noexcept(
is_nothrow_allocator_v<Alloc>);
template<class InputIt>
REXY_CPP20_CONSTEXPR
auto insert(const_iterator pos, InputIt start, InputIt last)noexcept(
is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<is_legacy_input_iterator_v<InputIt>,basic_string&>;
template<class InputIt>
REXY_CPP20_CONSTEXPR
auto insert(size_type pos, InputIt start, InputIt last)noexcept(
is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<is_legacy_input_iterator_v<InputIt>,basic_string&>;
REXY_CPP20_CONSTEXPR
basic_string& insert(const_iterator pos, std::initializer_list<value_type> list)noexcept(
is_nothrow_allocator_v<Alloc>);
template<class StringView>
REXY_CPP20_CONSTEXPR
auto insert(size_type pos, const StringView& sv)noexcept(
is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>> &&
!std::is_convertible_v<const StringView&, const_pointer>,
basic_string&>;
template<class StringView>
REXY_CPP20_CONSTEXPR
auto insert(size_type pos, const StringView& sv, size_type index_str, size_type count = npos)noexcept(
is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>> &&
!std::is_convertible_v<const StringView&,const_pointer>,
basic_string&>;
template<class InputIt>
REXY_CPP20_CONSTEXPR
auto append(InputIt start, InputIt fin)noexcept(
is_nothrow_allocator_v<Alloc>) ->
std::enable_if_t<is_legacy_input_iterator_v<InputIt>,basic_string&>;
REXY_CPP20_CONSTEXPR
basic_string& append(const_pointer data, size_type len)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& append(const_pointer data)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
basic_string& append(const basic_string& other)noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
void push_back(value_type data)noexcept(
is_nothrow_allocator_v<Alloc>);
constexpr void pop_back(void)noexcept;
constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str)noexcept;
constexpr basic_string& replace(const_iterator pos, const_iterator last, const basic_string& str)noexcept;
constexpr basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2 = npos)noexcept;
template<class InputIt>
constexpr auto replace(const_iterator first, const_iterator last, InputIt first2, InputIt last2)noexcept ->
std::enable_if_t<is_legacy_input_iterator_v<InputIt>,basic_string&>;
constexpr basic_string& replace(size_type pos, size_type count, const_pointer cstr, size_type count2)noexcept;
constexpr basic_string& replace(const_iterator first, const_iterator last, const_pointer cstr, size_type count)noexcept;
constexpr basic_string& replace(size_type pos, size_type count, const_pointer cstr)noexcept;
constexpr basic_string& replace(const_iterator first, const_iterator last, const_pointer cstr)noexcept;
constexpr basic_string& replace(size_type pos, size_type count, size_type count2, value_type v)noexcept;
constexpr basic_string& replace(const_iterator first, const_iterator last, size_type count2, value_type v)noexcept;
constexpr basic_string& replace(const_iterator first, const_iterator last, std::initializer_list<value_type> list)noexcept;
template<class StringView>
constexpr auto replace(size_type pos, size_type count, const StringView& sv)noexcept ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>> &&
!std::is_convertible_v<const StringView&,const_pointer>,
basic_string&>;
template<class StringView>
constexpr auto replace(const_iterator first, const_iterator last, const StringView& sv)noexcept ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>> &&
!std::is_convertible_v<const StringView&,const_pointer>,
basic_string&>;
template<class StringView>
constexpr auto replace(size_type pos, size_type count, const StringView& sv, size_type pos2, size_type count2 = npos)noexcept ->
std::enable_if_t<
std::is_convertible_v<const StringView&, basic_string_view<value_type>> &&
!std::is_convertible_v<const StringView&,const_pointer>,
basic_string&>;
constexpr basic_string& erase(size_type index = 0, size_type count = npos)noexcept;
constexpr iterator erase(const_iterator pos)noexcept;
constexpr iterator erase(const_iterator first, const_iterator last)noexcept;
template<REXY_ALLOCATOR_CONCEPT A = allocator_type>
REXY_CPP20_CONSTEXPR
basic_string<value_type,A> substring(size_type start, size_type end)const noexcept(
is_nothrow_allocator_v<A>);
REXY_CPP20_CONSTEXPR
basic_string substr(size_type start, size_type end)const noexcept(
is_nothrow_allocator_v<Alloc>);
REXY_CPP20_CONSTEXPR
pointer release(void)noexcept(
is_nothrow_allocator_v<Alloc>);
using detail::hasallocator<Alloc>::allocator;
}; //class basic_string
//Like an expression template but not really //Like an expression template but not really
template<class Left, class Right> template<class Left, class Right>
@ -705,21 +340,141 @@ namespace rexy{
constexpr string_cat_expr(string_cat_expr&&) = default; constexpr string_cat_expr(string_cat_expr&&) = default;
constexpr size_type length(void)const noexcept; constexpr size_type length(void)const noexcept;
template<REXY_ALLOCATOR_CONCEPT Alloc> template<class Alloc>
REXY_CPP20_CONSTEXPR operator basic_string<value_type,Alloc>(void)
operator basic_string<value_type,Alloc>(void)noexcept( noexcept(std::is_nothrow_constructible<basic_string<value_type,Alloc>, typename basic_string<value_type,Alloc>::size_type>::value &&
std::is_nothrow_constructible_v< std::is_nothrow_invocable<detail::string_appender<basic_string<value_type,Alloc>>,decltype(*this)>::value);
basic_string<value_type,Alloc>,
typename basic_string<value_type,Alloc>::size_type> &&
std::is_nothrow_invocable_v<
detail::string_appender<basic_string<value_type,Alloc>>,
decltype(*this)>);
}; };
template<class Left, class Right> template<class Left, class Right>
string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>; string_cat_expr(Left&&,Right&&) -> string_cat_expr<Left&&,Right&&>;
} //namespace rexy template<class Char>
class static_string : public string_base<Char>
{
public:
using value_type = typename string_base<Char>::value_type;
using size_type = typename string_base<Char>::size_type;
using difference_type = typename string_base<Char>::difference_type;
using pointer = typename string_base<Char>::pointer;
using const_pointer = typename string_base<Char>::const_pointer;
using reference = typename string_base<Char>::reference;
using const_reference = typename string_base<Char>::const_reference;
using iterator = typename string_base<Char>::iterator;
using const_iterator = typename string_base<Char>::const_iterator;
public:
constexpr static_string(void)noexcept;
constexpr static_string(const_pointer str, size_type len)noexcept;
constexpr static_string(const_pointer c)noexcept;
constexpr static_string(const static_string& s)noexcept;
constexpr static_string(static_string&& s)noexcept;
~static_string(void)noexcept = default;
constexpr static_string& operator=(const_pointer c)noexcept;
constexpr static_string& operator=(const static_string& s)noexcept;
constexpr static_string& operator=(static_string&&)noexcept;
};
template<class T>
static_string(const T*) -> static_string<T>;
template<class T>
static_string(const T*, size_t) -> static_string<T>;
template<class T>
struct is_string{
static constexpr bool value = rexy::is_template_derived_type<T,string_base>::value || rexy::is_template_type<T,string_cat_expr>::value;
};
template<class T>
struct is_concrete_string{
static constexpr bool value = rexy::is_template_derived_type<T,string_base>::value;
};
namespace detail{
template<class... Ts>
using enable_if_string = std::enable_if_t<(is_string<Ts>::value && ...),int>;
template<class... Ts>
using enable_if_concrete_string = std::enable_if_t<(is_concrete_string<Ts>::value && ...),int>;
template<class... Ts>
using enable_if_expr_string = std::enable_if_t<(rexy::is_template_type<Ts,string_cat_expr>::value && ...),int>;
} //namespace detail
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
constexpr bool operator==(Str1&& left, Str2&& right)noexcept{
return left.valid() && right.valid() && left.length() == right.length() && !strcmp(left.get(), right.get());
}
template<class Str, detail::enable_if_concrete_string<Str> = 0>
constexpr bool operator==(Str&& left, typename std::decay_t<Str>::const_pointer right)noexcept{
return left.valid() && right && !strcmp(left.get(), right);
}
template<class Str1, class Str2, detail::enable_if_concrete_string<Str1,Str2> = 0>
constexpr bool operator!=(Str1&& left, Str2&& right)noexcept{
return !(left == right);
}
template<class Str, detail::enable_if_concrete_string<Str> = 0>
constexpr bool operator!=(Str&& left, typename std::decay_t<Str>::const_pointer right)noexcept{
return !(left == right);
}
template<class Left, class Right, detail::enable_if_string<Left,Right> = 0>
constexpr auto operator+(Left&& l, Right&& r)
//uses deduction guide whereas std::is_nothrow_constructible couldn't
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(l), std::forward<Right>(r))))
{
return string_cat_expr(std::forward<Left>(l), std::forward<Right>(r));
}
template<class Right, detail::enable_if_string<Right> = 0>
constexpr auto operator+(typename std::decay_t<Right>::const_pointer left, Right&& right)
noexcept(noexcept(::new (nullptr) string_cat_expr(rexy::static_string(left), std::forward<Right>(right))))
{
return string_cat_expr(rexy::static_string(left), std::forward<Right>(right));
}
template<class Left, detail::enable_if_string<Left> = 0>
constexpr auto operator+(Left&& left, typename std::decay_t<Left>::const_pointer right)
noexcept(noexcept(::new (nullptr) string_cat_expr(std::forward<Left>(left), rexy::static_string(right))))
{
return rexy::string_cat_expr(std::forward<Left>(left), rexy::static_string(right));
}
template<class Left, class Right, detail::enable_if_concrete_string<Left> = 0, detail::enable_if_string<Right> = 0>
decltype(auto) operator+=(Left& l, Right&& r)
noexcept(noexcept(l + std::forward<Right>(r)) && std::is_nothrow_assignable<Left, decltype(l + std::forward<Right>(r))>::value)
{
return l = (l + std::forward<Right>(r));
}
template<class Left, detail::enable_if_concrete_string<Left> = 0>
decltype(auto) operator+=(Left& l, typename std::decay_t<Left>::const_pointer r)
noexcept(noexcept(l + r) && std::is_nothrow_assignable<Left, decltype(l + r)>::value)
{
return l = (l + r);
}
}
#include "string_base.tpp" #include "string_base.tpp"
namespace{
constexpr inline rexy::static_string<char> operator"" _ss(const char* str, size_t len)noexcept{
return rexy::static_string(str, len);
}
constexpr inline rexy::static_string<wchar_t> operator"" _ss(const wchar_t* str, size_t len)noexcept{
return rexy::static_string(str, len);
}
constexpr inline rexy::static_string<char16_t> operator"" _ss(const char16_t* str, size_t len)noexcept{
return rexy::static_string(str, len);
}
constexpr inline rexy::static_string<char32_t> operator"" _ss(const char32_t* str, size_t len)noexcept{
return rexy::static_string(str, len);
}
}
#ifdef REXY_BINARY_BASE_HPP
#include "detail/binary_string_conv.hpp"
#endif
#ifdef REXY_HASH_HPP
#include "static_string_hash.hpp"
#endif
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,19 +16,31 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_COMPAT_STRING_BASE_HPP #ifndef REXY_STRING_HASH_HPP
#define REXY_COMPAT_STRING_BASE_HPP #define REXY_STRING_HASH_HPP
#include <cstddef> //size_t #include "hash.hpp"
#include "rexy.hpp"
namespace rexy{ namespace rexy{
static constexpr std::size_t npos = std::size_t(-1);
//jenkns one at a time hash
template<class Str>
struct string_hash{
constexpr size_t operator()(const Str& s, size_t salt)const noexcept{
size_t hash = salt;
for(size_t i = 0;i < s.length();++i){
hash += s[i];
hash += (hash << 10);
hash += (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash << 11);
hash += (hash << 15);
return hash;
}
};
} }
#ifdef __cpp_concepts
#include "cpp20/string_base.hpp"
#else
#include "cpp17/string_base.hpp"
#endif
#endif #endif

View File

@ -1,191 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_STRING_VIEW_HPP
#define REXY_STRING_VIEW_HPP
#include <cstddef> //std::size_t, ptrdiff_t
#include <iterator> //reverse_iterator
#include "compat/standard.hpp"
#include "rexy.hpp"
namespace rexy{
template<class Char>
class string_base;
template<class Char>
class basic_string_view
{
public:
using value_type = Char;
using size_type = std::size_t;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = const_pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
static constexpr size_type npos = size_type(-1);
private:
const_pointer m_data = nullptr;
size_type m_length = 0;
public:
constexpr basic_string_view(void)noexcept = default;
constexpr basic_string_view(const_pointer str, size_type len)noexcept;
constexpr basic_string_view(const_pointer c)noexcept;
constexpr basic_string_view(const basic_string_view& s)noexcept = default;
constexpr basic_string_view(const string_base<Char>& s)noexcept;
constexpr basic_string_view(basic_string_view&& s)noexcept = default;
template<class InIter>
constexpr basic_string_view(InIter start, InIter fin)noexcept;
REXY_CPP20_CONSTEXPR ~basic_string_view(void)noexcept = default;
constexpr basic_string_view& operator=(const_pointer c)noexcept;
constexpr basic_string_view& operator=(const basic_string_view& s)noexcept = default;
constexpr basic_string_view& operator=(basic_string_view&&)noexcept = default;
//Length of string not including null terminator
constexpr size_type length(void)const noexcept{return m_length;}
constexpr size_type size(void)const noexcept{return m_length;}
//direct access to managed pointer
constexpr const_pointer c_str(void)const noexcept{return m_data;}
constexpr const_pointer data(void)const noexcept{return m_data;}
//true if m_data is not empty
constexpr bool valid(void)const noexcept{return m_length > 0;}
constexpr bool empty(void)const noexcept{return m_length == 0;}
constexpr const_reference operator[](size_type i)const noexcept{return m_data[i];}
constexpr const_reference at(size_type i)const noexcept{return m_data[i];}
constexpr const_reference front(void)const noexcept{return m_data[0];}
constexpr const_reference back(void)const noexcept{return m_data[m_length-1];}
constexpr const_iterator it_at(size_type i)const noexcept{return m_data + i;}
constexpr const_iterator search(basic_string_view s)const noexcept;
constexpr const_iterator search(const_pointer c)const noexcept;
template<class Searcher>
constexpr const_iterator search(basic_string_view s, const Searcher& searcher)const noexcept(
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_iterator, const_iterator>);
template<class Searcher>
constexpr const_iterator search(const_pointer c, const Searcher& searcher)const noexcept(
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_pointer, const_pointer>);
constexpr bool starts_with(basic_string_view sv)const noexcept;
constexpr bool starts_with(value_type v)const noexcept;
constexpr bool starts_with(const_pointer str)const noexcept;
constexpr bool ends_with(basic_string_view sv)const noexcept;
constexpr bool ends_with(value_type v)const noexcept;
constexpr bool ends_with(const_pointer str)const noexcept;
constexpr bool contains(basic_string_view sv)const noexcept;
constexpr bool contains(value_type sv)const noexcept;
constexpr bool contains(const_pointer str)const noexcept;
constexpr bool compare(const basic_string_view& s)const noexcept{return *this == s;}
constexpr bool compare(const_pointer c)const noexcept{return *this == c;}
constexpr const_iterator begin(void)const noexcept{return m_data;}
constexpr const_iterator end(void)const noexcept{return m_data+m_length;}
constexpr const_iterator cbegin(void)const noexcept{return begin();}
constexpr const_iterator cend(void)const noexcept{return end();}
constexpr const_reverse_iterator rbegin(void)const noexcept{return const_reverse_iterator(m_data+m_length);}
constexpr const_reverse_iterator rend(void)const noexcept{return const_reverse_iterator(m_data);}
constexpr const_reverse_iterator crbegin(void)const noexcept{return rbegin();}
constexpr const_reverse_iterator crend(void)const noexcept{return rend();}
constexpr void remove_prefix(size_type i)noexcept;
constexpr void remove_suffix(size_type i)noexcept;
constexpr basic_string_view substr(size_type pos, size_type count = npos)const noexcept;
constexpr size_type find_first_of(basic_string_view str, size_type pos = 0)const noexcept;
constexpr size_type find_first_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_first_of(const_pointer c, size_type pos = 0)const noexcept;
constexpr size_type find_first_of(const_pointer c, size_type pos, size_type size)const noexcept;
constexpr size_type find_first_not_of(basic_string_view str, size_type pos = 0)const noexcept;
constexpr size_type find_first_not_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_first_not_of(const_pointer c, size_type pos = 0)const noexcept;
constexpr size_type find_first_not_of(const_pointer c, size_type pos, size_type size)const noexcept;
constexpr size_type find_last_of(basic_string_view str, size_type pos = 0)const noexcept;
constexpr size_type find_last_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_last_of(const_pointer c, size_type pos = 0)const noexcept;
constexpr size_type find_last_of(const_pointer c, size_type pos, size_type size)const noexcept;
constexpr size_type find_last_not_of(basic_string_view str, size_type pos = 0)const noexcept;
constexpr size_type find_last_not_of(value_type v, size_type start = 0)const noexcept;
constexpr size_type find_last_not_of(const_pointer c, size_type pos = 0)const noexcept;
constexpr size_type find_last_not_of(const_pointer c, size_type pos, size_type size)const noexcept;
};
template<class T>
basic_string_view(const T*) -> basic_string_view<T>;
template<class T>
basic_string_view(const T*, std::size_t) -> basic_string_view<T>;
using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;
#ifndef LIBREXY_HEADER_ONLY
extern template class basic_string_view<char>;
extern template class basic_string_view<wchar_t>;
extern template class basic_string_view<char16_t>;
extern template class basic_string_view<char32_t>;
#endif
inline namespace str_literals{
constexpr inline rexy::basic_string_view<char> operator"" _sv(const char* str, std::size_t len)noexcept{
return rexy::basic_string_view(str, len);
}
constexpr inline rexy::basic_string_view<wchar_t> operator"" _sv(const wchar_t* str, std::size_t len)noexcept{
return rexy::basic_string_view(str, len);
}
constexpr inline rexy::basic_string_view<char16_t> operator"" _sv(const char16_t* str, std::size_t len)noexcept{
return rexy::basic_string_view(str, len);
}
constexpr inline rexy::basic_string_view<char32_t> operator"" _sv(const char32_t* str, std::size_t len)noexcept{
return rexy::basic_string_view(str, len);
}
}
}
namespace{
template<class Char>
std::ostream& operator<<(std::ostream& os, const rexy::basic_string_view<Char>& str){
return os << str.c_str();
}
}
#include "string_view.tpp"
#endif

View File

@ -1,242 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef REXY_STRING_VIEW_TPP
#define REXY_STRING_VIEW_TPP
#include "compat/to_address.hpp"
#include "utility.hpp"
#include "string_base.hpp"
#include "algorithm.hpp" //two_way_search
#include "compat/string_base.hpp"
namespace rexy{
template<class Char>
constexpr basic_string_view<Char>::basic_string_view(const_pointer str, size_type len)noexcept:
m_data(str), m_length(len){}
template<class Char>
constexpr basic_string_view<Char>::basic_string_view(const string_base<Char>& s)noexcept:
m_data(s.c_str()), m_length(s.length()){}
template<class Char>
template<class InIter>
constexpr basic_string_view<Char>::basic_string_view(InIter start, InIter fin)noexcept:
basic_string_view(compat::to_address(start), fin - start){}
template<class Char>
constexpr basic_string_view<Char>::basic_string_view(const_pointer c)noexcept:
basic_string_view(c, rexy::strlen(c)){}
template<class Char>
constexpr basic_string_view<Char>& basic_string_view<Char>::operator=(const_pointer c)noexcept{
m_data = c;
m_length = rexy::strlen(c);
return *this;
}
template<class Char>
constexpr auto basic_string_view<Char>::search(basic_string_view s)const noexcept -> const_iterator{
if(s.length() > m_length){
return cend();
}
return two_way_search(cbegin(), cend(), s.cbegin(), s.cend());
}
template<class Char>
constexpr auto basic_string_view<Char>::search(const_pointer c)const noexcept -> const_iterator{
basic_string_view tmp(c);
return search(tmp);
}
template<class Char>
template<class Searcher>
constexpr auto basic_string_view<Char>::search(basic_string_view s, const Searcher& searcher)const noexcept(
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_iterator, const_iterator>) -> const_iterator
{
if(s.length() > m_length){
return cend();
}
return searcher(cbegin(), cend(), s.cbegin(), s.cend());
}
template<class Char>
template<class Searcher>
constexpr auto basic_string_view<Char>::search(const_pointer c, const Searcher& searcher)const noexcept(
std::is_nothrow_invocable_v<Searcher, const_iterator, const_iterator, const_pointer, const_pointer>) -> const_iterator
{
basic_string_view tmp(c);
return search(tmp, searcher);
}
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(basic_string_view sv)const noexcept{
if(sv.length() > length()){
return false;
}
auto it = two_way_search(begin(), begin() + sv.length(), sv.cbegin(), sv.cend());
if(it == begin()){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(value_type v)const noexcept{
return front() == v;
}
template<class Char>
constexpr bool basic_string_view<Char>::starts_with(const_pointer s)const noexcept{
return starts_with(basic_string_view(s));
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(basic_string_view sv)const noexcept{
if(sv.length() > length()){
return false;
}
const auto start = end() - sv.length();
auto it = two_way_search(start, end(), sv.cbegin(), sv.cend());
if(it == start){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(value_type v)const noexcept{
return back() == v;
}
template<class Char>
constexpr bool basic_string_view<Char>::ends_with(const_pointer s)const noexcept{
return ends_with(basic_string_view(s));
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(basic_string_view sv)const noexcept{
const auto it = two_way_search(cbegin(), cend(), sv.cbegin(), sv.cend());
if(it != cend()){
return true;
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(value_type v)const noexcept{
for(size_type i = 0;i < length();++i){
if(m_data[i] == v){
return true;
}
}
return false;
}
template<class Char>
constexpr bool basic_string_view<Char>::contains(const_pointer str)const noexcept{
return contains(basic_string_view(str));
}
template<class Char>
constexpr basic_string_view<Char> basic_string_view<Char>::substr(size_type pos, size_type count)const noexcept{
const size_type real_count = rexy::min(count, length() - pos);
return basic_string_view{m_data + pos, real_count};
}
template<class Char>
constexpr void basic_string_view<Char>::remove_prefix(size_type i) noexcept{
if(i > m_length){
m_data = end();
m_length = 0;
}else{
m_data = begin() + i;
m_length -= i;
}
}
template<class Char>
constexpr void basic_string_view<Char>::remove_suffix(size_type i) noexcept{
if(i > m_length){
m_length = 0;
}else{
m_length -= i;
}
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_of(basic_string_view str, size_type pos)const noexcept -> size_type{
return rexy::find_first_of(*this, str.c_str(), pos, str.length());
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_of(value_type v, size_type start)const noexcept -> size_type{
return rexy::find_first_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_of(const_pointer c, size_type start)const noexcept -> size_type{
return rexy::find_first_of(*this, c, start, rexy::strlen(c));
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_of(const_pointer c, size_type start, size_type size)const noexcept -> size_type{
return rexy::find_first_of(*this, c, start, size);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_not_of(basic_string_view str, size_type pos)const noexcept -> size_type{
return rexy::find_first_not_of(*this, str.c_str(), pos, str.length());
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_not_of(value_type v, size_type start)const noexcept -> size_type{
return rexy::find_first_not_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_not_of(const_pointer c, size_type start)const noexcept -> size_type{
return rexy::find_first_not_of(*this, c, start, rexy::strlen(c));
}
template<class Char>
constexpr auto basic_string_view<Char>::find_first_not_of(const_pointer c, size_type start, size_type size)const noexcept -> size_type{
return rexy::find_first_not_of(*this, c, start, size);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_of(basic_string_view str, size_type pos)const noexcept -> size_type{
return rexy::find_last_of(*this, str.c_str(), pos, str.length());
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_of(value_type v, size_type start)const noexcept -> size_type{
return rexy::find_last_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_of(const_pointer c, size_type start)const noexcept -> size_type{
return rexy::find_last_of(*this, c, start, rexy::strlen(c));
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_of(const_pointer c, size_type start, size_type size)const noexcept -> size_type{
return rexy::find_last_of(*this, c, start, size);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_not_of(basic_string_view str, size_type pos)const noexcept -> size_type{
return rexy::find_last_not_of(*this, str.c_str(), pos, str.length());
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_not_of(value_type v, size_type start)const noexcept -> size_type{
return rexy::find_last_not_of(*this, &v, start, 1);
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_not_of(const_pointer c, size_type start)const noexcept -> size_type{
return rexy::find_last_not_of(*this, c, start, rexy::strlen(c));
}
template<class Char>
constexpr auto basic_string_view<Char>::find_last_not_of(const_pointer c, size_type start, size_type size)const noexcept -> size_type{
return rexy::find_last_not_of(*this, c, start, size);
}
}
#endif

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -29,7 +29,6 @@
#include <future> //future, packaged_task #include <future> //future, packaged_task
#include <functional> //function, bind #include <functional> //function, bind
#include <utility> //move, forward #include <utility> //move, forward
#include <type_traits> //invoke_result_t
#include "rexy.hpp" #include "rexy.hpp"
@ -63,14 +62,14 @@ namespace rexy{
void invalidate(void); void invalidate(void);
template<class Func, class... Args> template<class Func, class... Args>
auto add_job(Func&& f, Args&&... args) -> std::future<std::invoke_result_t<Func,Args...>>; auto add_job(Func&& f, Args&&... args) -> std::future<decltype(std::forward<Func>(f)(std::forward<Args>(args)...))>;
private: private:
void worker_loop(void); void worker_loop(void);
}; };
template<class Func, class... Args> template<class Func, class... Args>
auto threadpool::add_job(Func&& f, Args&&... args) -> std::future<std::invoke_result_t<Func,Args...>>{ auto threadpool::add_job(Func&& f, Args&&... args) -> std::future<decltype(std::forward<Func>(f)(std::forward<Args>(args)...))>{
using return_t = decltype(std::forward<Func>(f)(std::forward<Args>(args)...)); using return_t = decltype(std::forward<Func>(f)(std::forward<Args>(args)...));
using task_t = std::packaged_task<return_t(void)>; using task_t = std::packaged_task<return_t(void)>;

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -20,9 +20,7 @@
#define REXY_TRAITS_HPP #define REXY_TRAITS_HPP
#include <type_traits> //is_same, decay, integral_constant, declval #include <type_traits> //is_same, decay, integral_constant, declval
#include <iterator> //iterator_traits
#include "compat/traits.hpp"
#include "rexy.hpp" #include "rexy.hpp"
namespace rexy{ namespace rexy{
@ -32,7 +30,7 @@ namespace rexy{
static std::true_type check(U*); static std::true_type check(U*);
static std::false_type check(...); static std::false_type check(...);
static constexpr bool value = decltype(check(std::declval<std::decay_t<T>*>()))::value; static constexpr bool value = std::is_same<std::true_type,decltype(check(std::declval<std::decay_t<T>*>()))>::value;
}; };
template<class T, template<class...> class U> template<class T, template<class...> class U>
@ -56,86 +54,6 @@ namespace rexy{
}; };
template<class T, class = void>
struct is_dereferencable : public std::false_type{};
template<class T>
struct is_dereferencable<T,std::void_t<decltype(*(std::declval<T>()))>> : public std::true_type{};
template<class T>
static constexpr bool is_dereferencable_v = is_dereferencable<T>::value;
template<class T, class = void>
struct is_pointer_dereferencable : public std::false_type{};
template<class T>
struct is_pointer_dereferencable<T,std::void_t<decltype(std::declval<T>().operator->())>> : public std::true_type{};
template<class T>
struct is_pointer_dereferencable<T*,std::void_t<T*>> : public std::true_type{};
template<class T>
static constexpr bool is_pointer_dereferencable_v = is_pointer_dereferencable<T>::value;
template<class T, class = void>
struct is_prefix_incrementable : public std::false_type{};
template<class T>
struct is_prefix_incrementable<T,std::void_t<decltype(++(std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>()))>> : public std::true_type{};
template<class T>
static constexpr bool is_prefix_incrementable_v = is_prefix_incrementable<T>::value;
template<class T, class = void>
struct is_postfix_incrementable : public std::false_type{};
template<class T>
struct is_postfix_incrementable<T,std::void_t<decltype((std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>())++)>> : public std::true_type{};
template<class T>
static constexpr bool is_postfix_incrementable_v = is_postfix_incrementable<T>::value;
template<class T, class = void>
struct is_equality_comparable : public std::false_type{};
template<class T>
struct is_equality_comparable<T,std::void_t<decltype(std::declval<T>() == std::declval<T>())>> : public std::true_type{};
template<class T>
static constexpr bool is_equality_comparable_v = is_equality_comparable<T>::value;
template<class T, class = void>
struct is_inequality_comparable : public std::false_type{};
template<class T>
struct is_inequality_comparable<T,std::void_t<decltype(std::declval<T>() != std::declval<T>())>> : public std::true_type{};
template<class T>
static constexpr bool is_inequality_comparable_v = is_inequality_comparable<T>::value;
template<class T>
struct is_legacy_iterator{
static constexpr bool value = is_prefix_incrementable_v<T> && is_dereferencable_v<T>;
};
template<class T>
static constexpr bool is_legacy_iterator_v = is_legacy_iterator<T>::value;
template<class T, bool = is_legacy_iterator_v<T> &&
is_inequality_comparable_v<T> &&
is_pointer_dereferencable_v<T> &&
is_postfix_incrementable_v<T>>
struct is_legacy_input_iterator : public std::false_type{};
template<class T>
struct is_legacy_input_iterator<T,true>{
static constexpr bool value = std::is_convertible_v<decltype(std::declval<T>() == std::declval<T>()),bool> &&
std::is_same_v<decltype(*(std::declval<T>())),typename std::iterator_traits<T>::reference> &&
std::is_same_v<decltype(++std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>()),std::add_lvalue_reference_t<T>> &&
std::is_convertible_v<decltype(*std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>()++), typename std::iterator_traits<T>::value_type>;
};
template<class T>
static constexpr bool is_legacy_input_iterator_v = is_legacy_input_iterator<T>::value;
template<class T, class Value, bool = is_legacy_iterator_v<T> &&
is_postfix_incrementable_v<T>>
struct is_legacy_output_iterator : public std::false_type{};
template<class T, class Value>
struct is_legacy_output_iterator<T,Value,true>{
static constexpr bool value =
std::is_same_v<decltype(++std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>()),std::add_lvalue_reference_t<T>> &&
std::is_convertible_v<decltype(std::declval<std::add_lvalue_reference_t<remove_cvref_t<T>>>()++), std::add_lvalue_reference_t<std::add_const_t<T>>>;
};
template<class T, class Value>
static constexpr bool is_legacy_output_iterator_v = is_legacy_output_iterator<T,Value>::value;
} }
#endif #endif

View File

@ -20,18 +20,10 @@
#define REXY_UTILITY_HPP #define REXY_UTILITY_HPP
#include <utility> //forward, move #include <utility> //forward, move
#include <cstddef> //size_t #include <cstdlib> //size_t
#include <type_traits> //too many to enumerate #include <type_traits>
#include <string> //char_traits
#include "compat/if_consteval.hpp"
#include "rexy.hpp" #include "rexy.hpp"
#include "storage_for.hpp"
#ifdef REXY_if_consteval
#include <cstring> //strlen, strcmp, memcpy
#include <cwchar> //wcslen
#endif
namespace rexy{ namespace rexy{
@ -54,7 +46,7 @@ namespace rexy{
} }
return start2; return start2;
} }
template<class T, std::size_t N> template<class T, size_t N>
constexpr void swap(T (&l)[N], T (&r)[N]) constexpr void swap(T (&l)[N], T (&r)[N])
noexcept(noexcept(swap(*l, *r))) noexcept(noexcept(swap(*l, *r)))
{ {
@ -92,70 +84,11 @@ namespace rexy{
return cmp(l, r) ? l : r; return cmp(l, r) ? l : r;
} }
template<class T> template<class T>
constexpr T abs(const T& val){ constexpr size_t strlen(const T* c)noexcept{
return val > 0 ? val : -val; size_t i = 0;
for(;c[i];++i);
return i;
} }
template<class T>
constexpr std::size_t strlen(const T* c)noexcept{
return std::char_traits<T>::length(c);
}
#ifdef REXY_if_consteval
template<class T>
constexpr int strcmp(const T* l, const T* r)noexcept{
REXY_if_not_consteval{
if constexpr(std::is_same_v<std::remove_cvref_t<T>,char>){
return std::strcmp(l, r);
}else if constexpr(std::is_same_v<std::remove_cvref_t<T>,wchar_t>){
return std::wcscmp(l, r);
}
}
for(;*l == *r && *l;++l, ++r);
return *l - *r;
}
template<class T>
constexpr int strncmp(const T* l, const T* r, std::size_t max)noexcept{
REXY_if_not_consteval{
if constexpr(std::is_same_v<std::remove_cvref_t<T>,char>){
return std::strncmp(l, r, max);
}else if constexpr (std::is_same_v<std::remove_cvref_t<T>,wchar_t>){
return std::wcsncmp(l, r, max);
}
}
for(std::size_t i = 1;*l == *r && *l && i < max;++i, ++l, ++r);
return *l - *r;
}
template<class T, class Compare>
constexpr int strncmp(const T* l, const T* r, std::size_t max, Compare cmp)noexcept{
REXY_if_not_consteval{
if constexpr(std::is_same_v<std::remove_cvref_t<T>,char>){
return std::strncmp(l, r, max);
}else if constexpr (std::is_same_v<std::remove_cvref_t<T>,wchar_t>){
return std::wcsncmp(l, r, max);
}
}
for(std::size_t i = 1;cmp(l, r) && *l && i < max;++i, ++l, ++r);
return *l - *r;
}
template<class T, class Compare>
constexpr int strcmp(const T* l, const T* r, Compare cmp)noexcept{
for(;cmp(*l, *r) && *l;++l, ++r);
return *l - *r;
}
constexpr void memcpy(void* l, const void* r, std::size_t n){
REXY_if_not_consteval{
std::memcpy(l, r, n);
}else{
char* ld = static_cast<char*>(l);
const char* rd = static_cast<const char*>(r);
for(std::size_t i = 0;i < n;++i){
ld[i] = rd[i];
}
}
}
}
#else // REXY_if_consteval
template<class T> template<class T>
constexpr int strcmp(const T* l, const T* r)noexcept{ constexpr int strcmp(const T* l, const T* r)noexcept{
for(;*l == *r && *l;++l, ++r); for(;*l == *r && *l;++l, ++r);
@ -166,66 +99,14 @@ namespace rexy{
for(;cmp(*l, *r) && *l;++l, ++r); for(;cmp(*l, *r) && *l;++l, ++r);
return *l - *r; return *l - *r;
} }
template<class T> constexpr void memcpy(void* l, const void* r, size_t n){
constexpr int strncmp(const T* l, const T* r, std::size_t max)noexcept{
for(std::size_t i = 0;*l == *r && *l && i < max;++i, ++l, ++r);
return *l - *r;
}
constexpr void memcpy(void* l, const void* r, std::size_t n){
char* ld = static_cast<char*>(l); char* ld = static_cast<char*>(l);
const char* rd = static_cast<const char*>(r); const char* rd = static_cast<const char*>(r);
for(std::size_t i = 0;i < n;++i){ for(size_t i = 0;i < n;++i){
ld[i] = rd[i]; ld[i] = rd[i];
} }
} }
} }
#endif // REXY_if_consteval
template<class T>
struct constant_iterator
{
rexy::storage_for<T> val;
constexpr constant_iterator& operator++(void)noexcept{return *this;}
constexpr constant_iterator operator++(int)noexcept{return *this;}
constexpr T operator*(void)const noexcept{return val;}
constexpr bool operator==(const constant_iterator& other)const{return val == other.val;}
constexpr bool operator!=(const constant_iterator& other)const{return val != other.val;}
};
template<class T>
constant_iterator(T&&) -> constant_iterator<std::remove_cvref_t<T>>;
template<class T>
struct sized_constant_iterator
{
rexy::storage_for<T> val;
std::size_t count;
constexpr sized_constant_iterator& operator++(void)noexcept{
--count;
return *this;
}
constexpr sized_constant_iterator operator++(int)noexcept{
sized_constant_iterator other(*this);
--count;
return other;
}
constexpr const T& operator*(void)const noexcept{return val;}
constexpr bool operator==(const sized_constant_iterator& other)const{
return count == other.count;
}
constexpr bool operator!=(const sized_constant_iterator& other)const{
return !(*this == other);
}
};
template<class T>
sized_constant_iterator(T&&, std::size_t) -> sized_constant_iterator<std::remove_cvref_t<T>>;
} }

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,14 +16,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REXY_UTIL_DEMANGLE_HPP #include "rexy/binary.hpp"
#define REXY_UTIL_DEMANGLE_HPP #include "rexy/allocator.hpp"
#include <string>
namespace rexy{ namespace rexy{
std::string demangle(const char* name);
template class basic_binary<allocator<char>>;
} }
#endif

View File

@ -1,48 +0,0 @@
/**
This file is a part of rexy's general purpose library
Copyright (C) 2022 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rexy/demangle.hpp"
#if defined(__GNUC__) && !defined(_MSC_VER)
#include <cstdlib> //free
#include <string>
#include <memory> //unique_ptr
#include <cxxabi.h> //__cxa_demangle
namespace util{
std::string demangle(const char* name){
int status = 0;
std::unique_ptr<char,void(*)(void*)> res{
abi::__cxa_demangle(name, nullptr, nullptr, &status),
std::free
};
return (status == 0) ? res.get() : name;
}
}
#else
#include <string>
namespace util{
std::string demangle(const char* name){
return name;
}
}
#endif

View File

@ -1,36 +1,24 @@
//Never actually used in the project. This just ensures that all syntax is correct during builds. //Never actually used in the project. This just ensures that all syntax is correct during builds.
#include "rexy/rexy.hpp"
#include "rexy/algorithm.hpp" #include "rexy/algorithm.hpp"
#include "rexy/allocator.hpp" #include "rexy/allocator.hpp"
#include "rexy/buffer.hpp" #include "rexy/binary.hpp"
#include "rexy/buffer.tpp" #include "rexy/binary_base.hpp"
#include "rexy/binary_base.tpp"
#include "rexy/expression.hpp" #include "rexy/expression.hpp"
#include "rexy/filerd.hpp"
#include "rexy/hash.hpp" #include "rexy/hash.hpp"
#include "rexy/mpmc_queue.hpp" #include "rexy/mpmc_queue.hpp"
#include "rexy/steal.hpp" #include "rexy/steal.hpp"
#include "rexy/string_base.hpp" #include "rexy/string_base.hpp"
#include "rexy/string_base.tpp" #include "rexy/string_base.tpp"
#include "rexy/string_hash.hpp"
#include "rexy/string.hpp" #include "rexy/string.hpp"
#include "rexy/traits.hpp" #include "rexy/traits.hpp"
#include "rexy/utility.hpp" #include "rexy/utility.hpp"
#include "rexy/meta.hpp" #include "rexy/meta.hpp"
#include "rexy/enum_traits.hpp"
#include "rexy/deferred.hpp"
#include "rexy/debug_print.hpp"
#include "rexy/storage_for.hpp"
#include "rexy/visitor.hpp"
#include "rexy/string_view.hpp"
#include "rexy/string_view.tpp"
#include "rexy/list.hpp"
#include "rexy/list.tpp"
#ifndef LIBREXY_HEADER_ONLY
#include "rexy/filerd.hpp"
#include "rexy/threadpool.hpp"
#include "rexy/demangle.hpp"
#endif
#include "rexy/detail/binary_string_conv.hpp"
#include "rexy/detail/string_appender.hpp" #include "rexy/detail/string_appender.hpp"
#include "rexy/cx/array.hpp" #include "rexy/cx/array.hpp"
@ -39,6 +27,3 @@
#include "rexy/cx/vector.hpp" #include "rexy/cx/vector.hpp"
#include "rexy/cx/detail/bool_specialize_base.hpp" #include "rexy/cx/detail/bool_specialize_base.hpp"
#include "rexy/compat/to_address.hpp"
#include "rexy/compat/source_location.hpp"

View File

@ -1,6 +1,6 @@
/** /**
This file is a part of rexy's general purpose library This file is a part of rexy's general purpose library
Copyright (C) 2020-2022 rexy712 Copyright (C) 2020 rexy712
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -16,12 +16,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifdef _MSC_VER
//Disable warning from msvc for not using fopen_s
//which is not standard in c++ as of c++23, though it is in c since c11.
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "rexy/filerd.hpp" #include "rexy/filerd.hpp"
#include <cstdio> //fopen, fclose #include <cstdio> //fopen, fclose
@ -31,99 +25,89 @@
namespace rexy{ namespace rexy{
filerd::filerd(const char* f, const char* mode)noexcept: filerd::filerd(const char* f, const char* mode)noexcept:
m_fp(std::fopen(f, mode)){} m_fp(fopen(f, mode)){}
filerd::~filerd(void)noexcept{ filerd::~filerd(void)noexcept{
if(m_fp) if(m_fp)
std::fclose(m_fp); fclose(m_fp);
} }
void filerd::reset(std::FILE* fp)noexcept{ void filerd::reset(FILE* fp)noexcept{
if(m_fp) if(m_fp)
std::fclose(m_fp); fclose(m_fp);
m_fp = fp; m_fp = fp;
} }
std::FILE* filerd::release(void)noexcept{ FILE* filerd::release(void)noexcept{
return std::exchange(m_fp, nullptr); return std::exchange(m_fp, nullptr);
} }
std::size_t filerd::length(void)noexcept{ size_t filerd::length(void)noexcept{
if(!m_fp) if(!m_fp)
return 0; return 0;
std::size_t tmp, ret; size_t tmp, ret;
tmp = std::ftell(m_fp); tmp = ftell(m_fp);
std::fseek(m_fp, 0, SEEK_END); fseek(m_fp, 0, SEEK_END);
ret = std::ftell(m_fp); ret = ftell(m_fp);
std::fseek(m_fp, long(tmp), SEEK_SET); fseek(m_fp, tmp, SEEK_SET);
return ret; return ret;
} }
std::size_t filerd::position(void)const noexcept{ size_t filerd::position(void)const noexcept{
return std::ftell(m_fp); return ftell(m_fp);
} }
void filerd::rewind(std::size_t pos)noexcept{ void filerd::rewind(size_t pos)noexcept{
std::fseek(m_fp, long(pos), SEEK_SET); fseek(m_fp, pos, SEEK_SET);
} }
filerd::operator std::FILE*(void)noexcept{ filerd::operator FILE*(void)noexcept{
return m_fp; return m_fp;
} }
filerd::operator const std::FILE*(void)const noexcept{ filerd::operator const FILE*(void)const noexcept{
return m_fp; return m_fp;
} }
std::FILE* filerd::get(void)noexcept{ FILE* filerd::get(void)noexcept{
return m_fp; return m_fp;
} }
const std::FILE* filerd::get(void)const noexcept{ const FILE* filerd::get(void)const noexcept{
return m_fp; return m_fp;
} }
filerd::operator bool(void)const noexcept{ filerd::operator bool(void)const noexcept{
return m_fp; return m_fp;
} }
bool filerd::eof(void)const{ size_t filerd::read(char* dest, size_t bytes)noexcept{
return m_finished; return fread(dest, 1, bytes, m_fp);
} }
rexy::string filerd::read(size_t bytes)noexcept{
std::size_t filerd::read(char* dest, std::size_t bytes)noexcept{
const auto rdcnt = std::fread(dest, 1, bytes, m_fp);
if(rdcnt < bytes){
m_finished = true;
}
return rdcnt;
}
rexy::string filerd::read(std::size_t bytes)noexcept{
rexy::string ret; rexy::string ret;
char* tmp = ret.allocator().allocate(bytes); char* tmp = ret.allocator().allocate(bytes);
std::size_t written = read(tmp, bytes); size_t written = read(tmp, bytes);
ret.reset(tmp, written); ret.reset(tmp, written);
return ret; return ret;
} }
rexy::string filerd::readln(std::size_t max)noexcept{ rexy::string filerd::readln(size_t max)noexcept{
rexy::string ret; rexy::string ret;
int c; int c;
std::size_t count = 0; size_t count = 0;
for(c = std::fgetc(m_fp);c != EOF && c != '\n';c = std::fgetc(m_fp)){ for(c = fgetc(m_fp);c != EOF && c != '\n';c = fgetc(m_fp)){
char ch = c; char ch = c;
ret.append(&ch, 1); ret.append(&ch, 1);
if(++count == max) if(++count == max)
break; break;
} }
if(c == EOF){
m_finished = true;
}
return ret; return ret;
} }
rexy::buffer<char> filerd::read_bin(std::size_t bytes) rexy::binary filerd::read_bin(size_t bytes)
noexcept(std::is_nothrow_constructible<rexy::buffer<char>, char*, std::size_t>::value) noexcept(std::is_nothrow_constructible<rexy::binary, rexy::steal<char*>, size_t, size_t>::value)
{ {
rexy::buffer<char> ret{bytes}; rexy::binary ret;
const auto written = read(ret.data(), bytes); char* tmp = ret.allocator().allocate(bytes);
ret.set_size(written); size_t written = read(tmp, bytes);
ret.reset(tmp, written);
return ret; return ret;
} }
std::size_t filerd::write(const char* c, std::size_t bytes)noexcept{ size_t filerd::write(const char* c, size_t bytes)noexcept{
return std::fwrite(c, 1, bytes, m_fp); return fwrite(c, 1, bytes, m_fp);
} }
std::size_t filerd::write(rexy::string_view c)noexcept{ size_t filerd::write(const rexy::string_base<char>& c)noexcept{
return write(c.data(), c.length()); return write(c.get(), c.length());
} }
} }

View File

@ -16,13 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "rexy/string_view.hpp" #include "rexy/string_base.hpp"
namespace rexy{ namespace rexy{
template class basic_string_view<char>; template class static_string<char>;
template class basic_string_view<wchar_t>; template class static_string<wchar_t>;
template class basic_string_view<char16_t>; template class static_string<char16_t>;
template class basic_string_view<char32_t>; template class static_string<char32_t>;
} }

Some files were not shown because too many files have changed in this diff Show More