Initial commit
This commit is contained in:
commit
066d875f91
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
tester
|
||||||
|
lib*.a
|
||||||
|
lib*.so
|
||||||
|
build
|
||||||
|
*.swp
|
||||||
|
obj
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
test.cpp
|
||||||
|
tester.cpp
|
||||||
227
makefile
Normal file
227
makefile
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
#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/>.
|
||||||
|
|
||||||
|
#Copyright 2018-2020 rexy712
|
||||||
|
|
||||||
|
#Makefile to generate a single static or shared library from all the sources in SOURCE_DIRS ending in EXT
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
WINDOWS::=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
SOURCE_DIRS::=rexy
|
||||||
|
SOURCES::=
|
||||||
|
OBJDIR::=obj
|
||||||
|
DEPDIR::=$(OBJDIR)/dep
|
||||||
|
LIBDIR::=lib
|
||||||
|
INCLUDE_DIRS::=.
|
||||||
|
CFLAGS::=-g -std=c18 -Wall -pedantic -Wextra
|
||||||
|
CXXFLAGS::=-g -std=c++17 -Wall -pedantic -Wextra
|
||||||
|
EXT::=cpp
|
||||||
|
LANG::=$(EXT)
|
||||||
|
MAIN_LIBRARY::=rexy
|
||||||
|
PRE_TARGETS::=
|
||||||
|
POST_TARGETS::=
|
||||||
|
CLEAN_TARGETS::=clean_tester
|
||||||
|
SHARED?=1
|
||||||
|
STATIC?=0
|
||||||
|
RELEASE?=0
|
||||||
|
MEMCHK?=0
|
||||||
|
|
||||||
|
ifneq ($(WINDOWS),1)
|
||||||
|
#*nix settings
|
||||||
|
CC::=gcc
|
||||||
|
CXX::=g++
|
||||||
|
LDLIBS::=
|
||||||
|
LDFLAGS::=
|
||||||
|
STRIP::=strip
|
||||||
|
RANLIB::=ranlib
|
||||||
|
AR::=ar
|
||||||
|
AS::=as
|
||||||
|
else #windows
|
||||||
|
#windows settings
|
||||||
|
#windows is a fuckwit
|
||||||
|
MINGW_PREFIX::=x86_64-w64-mingw32-
|
||||||
|
CC::=$(MINGW_PREFIX)gcc
|
||||||
|
CXX::=$(MINGW_PREFIX)g++
|
||||||
|
LDLIBS::=
|
||||||
|
LDFLAGS::=-static-libgcc -static-libstdc++
|
||||||
|
STRIP::=$(MINGW_PREFIX)strip
|
||||||
|
RANLIB::=$(MINGW_PREFIX)ranlib
|
||||||
|
AR::=$(MINGW_PREFIX)ar
|
||||||
|
AS::=$(MINGW_PREFIX)as
|
||||||
|
endif #windows
|
||||||
|
|
||||||
|
#Put your custom targets for PRE_TARGETS and POST_TARGETS here:
|
||||||
|
|
||||||
|
tester: all
|
||||||
|
$(CXX) tester.cpp -o tester $(CXXFLAGS) $(LDFLAGS) -L. -lrexy -I.
|
||||||
|
|
||||||
|
clean_tester:
|
||||||
|
$(call rm,tester)
|
||||||
|
|
||||||
|
###########################################################################################################
|
||||||
|
#Everything past this point is internal BS, probably best not to touch it unless you know what you're doing
|
||||||
|
|
||||||
|
#set the all target as the default target, otherwise the topmost target will run
|
||||||
|
.DEFAULT_GOAL::=all
|
||||||
|
|
||||||
|
#setup the actual output library name depending on shared/static and windows/anything else
|
||||||
|
ifeq ($(WINDOWS),1)
|
||||||
|
INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).a
|
||||||
|
else
|
||||||
|
INTERNAL_SHARED_LIBRARY::=lib$(MAIN_LIBRARY).so
|
||||||
|
endif
|
||||||
|
SHARED_LIBRARY_FLAGS=-fPIC
|
||||||
|
DLLOUT::=$(MAIN_LIBRARY).dll
|
||||||
|
INTERNAL_STATIC_LIBRARY::=lib$(MAIN_LIBRARY).a
|
||||||
|
|
||||||
|
|
||||||
|
#system dependant bullshit
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
#windows' cmd commands
|
||||||
|
mkdir=mkdir $(subst /,\,$(1)) > NUL 2>&1
|
||||||
|
rm=del /F $(1) > NUL 2>&1
|
||||||
|
rmdir=rd /S /Q $(1) > NUL 2>&1
|
||||||
|
move=move /Y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
|
||||||
|
copy=copy /Y /B $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1
|
||||||
|
else
|
||||||
|
#*nix terminal commands
|
||||||
|
mkdir=mkdir -p $(1)
|
||||||
|
rm=rm -f $(1)
|
||||||
|
rmdir=rm -rf $(1)
|
||||||
|
move=mv $(1) $(2)
|
||||||
|
copy=cp $(1) $(2)
|
||||||
|
endif
|
||||||
|
|
||||||
|
#setup compiler and flags based on language
|
||||||
|
ifeq ($(LANG),cpp)
|
||||||
|
COMPILER_FLAGS::=$(CXXFLAGS)
|
||||||
|
COMPILER::=$(CXX)
|
||||||
|
else ifeq ($(LANG),c)
|
||||||
|
COMPILER_FLAGS::=$(CFLAGS)
|
||||||
|
COMPILER::=$(CC)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(RELEASE),1)
|
||||||
|
#a lot of false strict aliasing warnings from gcc 9
|
||||||
|
COMPILER_FLAGS+=-O2 -Wno-strict-aliasing
|
||||||
|
POST_TARGETS+= do_strip
|
||||||
|
else ifeq ($(MEMCHK),1)
|
||||||
|
#use asan to check memory leaks/invalid accesses
|
||||||
|
LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||||
|
COMPILER_FLAGS+=-O0 -g3 -ggdb -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls
|
||||||
|
else
|
||||||
|
#default target
|
||||||
|
COMPILER_FLAGS+=-O0 -g3 -ggdb
|
||||||
|
endif
|
||||||
|
|
||||||
|
#add dependency tracking and include directories
|
||||||
|
INTERNAL_COMPILERFLAGS=-c $(foreach dir,$(INCLUDE_DIRS),-I"$(dir)") -MMD -MP -MF"$(DEPDIR)/$(notdir $(patsubst %.o,%.d,$@))"
|
||||||
|
ifeq ($(SHARED),1)
|
||||||
|
INTERNAL_COMPILERFLAGS+=$(SHARED_LIBRARY_FLAGS)
|
||||||
|
endif
|
||||||
|
THIS_MAKEFILE_NAME::=$(lastword $(MAKEFILE_LIST))
|
||||||
|
INTERNAL_SOURCES::=$(SOURCES) $(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext))))
|
||||||
|
OBJECTS+=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(INTERNAL_SOURCES)))))
|
||||||
|
|
||||||
|
#Arguments to make submake use this makefile without "Entering directory" stuff
|
||||||
|
SUBMAKE_ARGUMENTS::=--no-print-directory -f "$(THIS_MAKEFILE_NAME)"
|
||||||
|
#just a variable for a newline
|
||||||
|
define \n
|
||||||
|
|
||||||
|
|
||||||
|
endef
|
||||||
|
|
||||||
|
#default target: run targets in PRE_TARGETS, then build the main library, then POST_TARGETS
|
||||||
|
.PHONY: all
|
||||||
|
all:
|
||||||
|
$(foreach target,$(PRE_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n))
|
||||||
|
ifeq ($(SHARED),1)
|
||||||
|
ifeq ($(WINDOWS),1)
|
||||||
|
@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(DLLOUT)"
|
||||||
|
else #windows
|
||||||
|
@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_SHARED_LIBRARY)"
|
||||||
|
endif #windows
|
||||||
|
endif #shared
|
||||||
|
ifeq ($(STATIC),1)
|
||||||
|
ifeq ($(SHARED),1)
|
||||||
|
@$(MAKE) $(SUBMAKE_ARGUMENTS) "object_clean"
|
||||||
|
endif #shared
|
||||||
|
@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(INTERNAL_STATIC_LIBRARY)" SHARED=0
|
||||||
|
endif #static
|
||||||
|
$(foreach target,$(POST_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n))
|
||||||
|
|
||||||
|
ifeq ($(WINDOWS),1)
|
||||||
|
#target for windows shared library
|
||||||
|
$(DLLOUT): $(OBJECTS)
|
||||||
|
$(COMPILER) -shared -o "$(DLLOUT)" $^ -Wl,--out-implib,"lib$(MAIN_LIBRARY).a" $(SHARED_LIBRARY_FLAGS) $(LDLIBS) $(LDFLAGS)
|
||||||
|
else #windows
|
||||||
|
|
||||||
|
#target for *nix shared library
|
||||||
|
$(INTERNAL_SHARED_LIBRARY): $(OBJECTS)
|
||||||
|
$(COMPILER) -shared -o "$@" $^ $(COMPILER_FLAGS) $(SHARED_LIBRARY_FLAGS) $(LDFLAGS) $(LDLIBS)
|
||||||
|
endif #windows
|
||||||
|
|
||||||
|
#target for static library
|
||||||
|
$(INTERNAL_STATIC_LIBRARY): $(OBJECTS)
|
||||||
|
$(AR) rcs "$@" $^
|
||||||
|
$(RANLIB) "$@"
|
||||||
|
|
||||||
|
|
||||||
|
#Called in POST_TARGETS when RELEASE=1
|
||||||
|
.PHONY: do_strip
|
||||||
|
do_strip:
|
||||||
|
ifeq ($(SHARED),1)
|
||||||
|
$(STRIP) --strip-debug "$(INTERNAL_SHARED_LIBRARY)"
|
||||||
|
endif
|
||||||
|
ifeq ($(STATIC),1)
|
||||||
|
$(STRIP) --strip-debug "$(INTERNAL_STATIC_LIBRARY)"
|
||||||
|
endif
|
||||||
|
|
||||||
|
#Object target recipe
|
||||||
|
define GENERATE_OBJECTS
|
||||||
|
$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/%
|
||||||
|
$$(COMPILER) $$(COMPILER_FLAGS) $$(INTERNAL_COMPILERFLAGS) "$$<" -o "$$@"
|
||||||
|
endef
|
||||||
|
define GENERATE_INDIVIDUAL_OBJECTS
|
||||||
|
$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).o: $(1)
|
||||||
|
$$(COMPILER) $$(COMPILER_FLAGS) $$(INTERNAL_COMPILERFLAGS) "$$<" -o "$$@"
|
||||||
|
endef
|
||||||
|
|
||||||
|
|
||||||
|
#Create targets for object files
|
||||||
|
$(foreach dir,$(SOURCE_DIRS),$(eval $(call GENERATE_OBJECTS,$(dir))))
|
||||||
|
$(foreach src,$(SOURCES),$(eval $(call GENERATE_INDIVIDUAL_OBJECTS,$(src))))
|
||||||
|
$(OBJECTS): | $(OBJDIR) $(DEPDIR)
|
||||||
|
|
||||||
|
$(OBJDIR):
|
||||||
|
$(call mkdir,"$@")
|
||||||
|
$(DEPDIR):
|
||||||
|
$(call mkdir,"$@")
|
||||||
|
|
||||||
|
.PHONY: object_clean
|
||||||
|
object_clean:
|
||||||
|
$(call rmdir,"$(OBJDIR)")
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean: object_clean
|
||||||
|
$(foreach target,$(CLEAN_TARGETS),@$(MAKE) $(SUBMAKE_ARGUMENTS) "$(target)"$(\n))
|
||||||
|
$(call rmdir,"$(DEPDIR)")
|
||||||
|
$(call rm,"lib$(MAIN_LIBRARY).so")
|
||||||
|
$(call rm,"lib$(MAIN_LIBRARY).a")
|
||||||
|
$(call rm,"$(DLLOUT)")
|
||||||
|
|
||||||
|
#header file dep tracking
|
||||||
|
-include $(wildcard $(DEPDIR)/*.d)
|
||||||
|
|
||||||
37
rexy/binary.cpp
Normal file
37
rexy/binary.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "binary.hpp"
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
binary_base::binary_base(binary_base&& b):
|
||||||
|
m_data(std::exchange(b.m_data, nullptr)),
|
||||||
|
m_size(b.m_size),
|
||||||
|
m_cap(b.m_cap){}
|
||||||
|
|
||||||
|
char* binary_base::release(void){
|
||||||
|
return std::exchange(m_data, nullptr);
|
||||||
|
}
|
||||||
|
char& binary_base::operator[](size_t i){
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
const char& binary_base::operator[](size_t i)const{
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
172
rexy/binary.hpp
Normal file
172
rexy/binary.hpp
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_BINARY_HPP
|
||||||
|
#define REXY_BINARY_HPP
|
||||||
|
|
||||||
|
#include <cstdlib> //size_t
|
||||||
|
#include <utility> //move
|
||||||
|
#include <cstring> //memcpy
|
||||||
|
#include <algorithm> //max
|
||||||
|
#include <type_traits>
|
||||||
|
#include <new>
|
||||||
|
#include <rexy/detail/default_allocator.hpp>
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
class binary_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
char* m_data = nullptr;
|
||||||
|
size_t m_size = 0;
|
||||||
|
size_t m_cap = 0;
|
||||||
|
public:
|
||||||
|
protected:
|
||||||
|
constexpr binary_base(void) = default;
|
||||||
|
constexpr binary_base(char* data, size_t size):
|
||||||
|
m_data(data), m_cap(size){}
|
||||||
|
constexpr binary_base(char* data, size_t cap, size_t size):
|
||||||
|
m_data(data), m_size(size), m_cap(cap){}
|
||||||
|
template<class Allocator>
|
||||||
|
binary_base(const binary_base& b):
|
||||||
|
m_data(Allocator::copy(b.m_data, b.m_cap)),
|
||||||
|
m_size(b.m_size),
|
||||||
|
m_cap(b.m_cap){}
|
||||||
|
binary_base(binary_base&&);
|
||||||
|
~binary_base(void) = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
char* release(void);
|
||||||
|
|
||||||
|
constexpr size_t size(void)const{return m_size;}
|
||||||
|
constexpr size_t capacity(void)const{return m_cap;}
|
||||||
|
constexpr char* get(void){return m_data;}
|
||||||
|
constexpr const char* get(void)const{return m_data;}
|
||||||
|
constexpr operator bool(void)const{return m_data;}
|
||||||
|
|
||||||
|
char& operator[](size_t i);
|
||||||
|
const char& operator[](size_t i)const;
|
||||||
|
|
||||||
|
};
|
||||||
|
template<class Allocator = detail::default_allocator<>>
|
||||||
|
class binary_data : public binary_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
public:
|
||||||
|
constexpr binary_data(void) = default;
|
||||||
|
binary_data(char* data, size_t size):
|
||||||
|
binary_base(data, size){}
|
||||||
|
binary_data(const char* data, size_t size):
|
||||||
|
binary_base(reinterpret_cast<char*>(Allocator::copy(data, size)), size){}
|
||||||
|
binary_data(char* data, size_t cap, size_t size):
|
||||||
|
binary_base(data, cap, size){}
|
||||||
|
binary_data(const char* data, size_t cap, size_t size):
|
||||||
|
binary_base(reinterpret_cast<char*>(Allocator::copy(data, size)), cap, size){}
|
||||||
|
binary_data(size_t size):
|
||||||
|
binary_base(reinterpret_cast<char*>(Allocator::allocate(size)), size){}
|
||||||
|
binary_data(const binary_data& b):
|
||||||
|
binary_base(b)
|
||||||
|
{
|
||||||
|
m_data = Allocator::copy(b.m_data, b.m_cap);
|
||||||
|
}
|
||||||
|
binary_data(binary_data&& b):
|
||||||
|
binary_base(std::move(b)){}
|
||||||
|
~binary_data(void){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
}
|
||||||
|
binary_data& operator=(const binary_data& b){
|
||||||
|
binary_data tmp(b);
|
||||||
|
return (*this = std::move(tmp));
|
||||||
|
}
|
||||||
|
binary_data& operator=(binary_data&& b){
|
||||||
|
m_size = b.m_size;
|
||||||
|
m_cap = b.m_cap;
|
||||||
|
std::swap(m_data, b.m_data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void reset(void){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_data = nullptr;
|
||||||
|
m_cap = m_size = 0;
|
||||||
|
}
|
||||||
|
void reset(char* val, size_t cap, size_t size = 0){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_data = val;
|
||||||
|
m_cap = cap;
|
||||||
|
m_size = size;
|
||||||
|
}
|
||||||
|
bool resize(size_t newsize){
|
||||||
|
if(newsize < m_cap)
|
||||||
|
return false;
|
||||||
|
binary_data tmp(newsize);
|
||||||
|
if(!tmp)
|
||||||
|
return false;
|
||||||
|
memcpy(tmp.m_data, m_data, m_size);
|
||||||
|
std::swap(m_data, tmp.m_data);
|
||||||
|
m_cap = tmp.m_cap;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void append(const char* data, size_t len){
|
||||||
|
if(m_size + len > m_cap)
|
||||||
|
resize(std::max(m_cap*2, m_size+len));
|
||||||
|
memcpy(m_data+m_size, data, len);
|
||||||
|
m_size += len;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using binary = binary_data<>;
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
std::true_type is_binary_type_helper(binary_base);
|
||||||
|
std::false_type is_binary_type_helper(...);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_binary_type{
|
||||||
|
constexpr static bool value = std::is_same<decltype(is_binary_type_helper(std::declval<typename std::decay<T>::type>())),std::true_type>::value;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Left, class Right, typename std::enable_if<rexy::detail::is_binary_type<Left>::value && rexy::detail::is_binary_type<Right>::value,void>::type* = nullptr>
|
||||||
|
bool operator==(Left&& l, Right&& r){
|
||||||
|
return l && r && l.size() == r.size() && l.capacity() == r.capacity() && !memcmp(l.get(), r.get(), l.size());
|
||||||
|
}
|
||||||
|
template<class Left, class Right, typename std::enable_if<rexy::detail::is_binary_type<Left>::value && rexy::detail::is_binary_type<Right>::value,void>::type* = nullptr>
|
||||||
|
bool operator!=(Left&& l, Right&& r){
|
||||||
|
return !(std::forward<Left>(l) == std::forward<Right>(r));
|
||||||
|
}
|
||||||
|
template<class All, class Alr>
|
||||||
|
auto operator+(const rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r){
|
||||||
|
rexy::binary_data<All> retval(l.size() + r.size());
|
||||||
|
memcpy(retval.get(), l.get(), l.size());
|
||||||
|
memcpy(retval.get()+l.size(), r.get(), r.size());
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
template<class All, class Alr>
|
||||||
|
decltype(auto) operator+=(rexy::binary_data<All>& l, const rexy::binary_data<Alr>& r){
|
||||||
|
l.resize(l.size() + r.size());
|
||||||
|
memcpy(l.get()+l.size(), r.get(), r.size());
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REXY_STRING_BASE_HPP
|
||||||
|
#include <rexy/detail/binary_string_conv.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
71
rexy/detail/binary_string_conv.hpp
Normal file
71
rexy/detail/binary_string_conv.hpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero 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.hpp>
|
||||||
|
#include <rexy/binary.hpp>
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
template<class Al, class Str = rexy::string, typename std::enable_if<rexy::detail::is_concrete_string<Str>::value,void>::type* = nullptr>
|
||||||
|
auto binary_to_string(const binary_data<Al>& b){
|
||||||
|
Str s(b.size()+1);
|
||||||
|
memcpy(s.get(), b.get(), b.size());
|
||||||
|
s[b.size()] = 0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<class Al, class Str = rexy::string, typename std::enable_if<rexy::detail::is_concrete_string<Str>::value && std::is_same<typename std::decay<Al>::type,typename Str::allocator_type>::value,void>::type* = nullptr>
|
||||||
|
auto binary_to_string(binary_data<Al>&& b){
|
||||||
|
Str s;
|
||||||
|
s.reset(b.get(), b.size());
|
||||||
|
b.release();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
template<class Bin = rexy::binary, typename std::enable_if<rexy::detail::is_binary_type<Bin>::value,void>::type* = nullptr>
|
||||||
|
auto string_to_binary(const string_base& s){
|
||||||
|
Bin b(s.length()+1);
|
||||||
|
b.append(s.get(), s.length()+1);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
template<class Al, class Bin = rexy::binary, typename std::enable_if<rexy::detail::is_binary_type<Bin>::value && std::is_same<typename std::decay<Al>::type,typename Bin::allocator_type>::value,void>::type* = nullptr>
|
||||||
|
auto string_to_binary(string_intermediary<Al>&& s){
|
||||||
|
Bin b;
|
||||||
|
b.reset(s.get(), s.length()+1);
|
||||||
|
s.release();
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class L, class R, typename std::enable_if<rexy::detail::is_binary_type<L>::value && rexy::detail::is_concrete_string<R>::value,void>::type* = nullptr>
|
||||||
|
decltype(auto) operator+=(L& l, R&& r){
|
||||||
|
l.append(r.get(), r.length()+1);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
template<class L, class R, typename std::enable_if<rexy::detail::is_binary_type<L>::value && rexy::detail::is_string<R>::value && !rexy::detail::is_concrete_string<R>::value,void>::type* = nullptr>
|
||||||
|
decltype(auto) operator+=(L& l, R&& r){
|
||||||
|
rexy::string concrete = r;
|
||||||
|
return (l = concrete);
|
||||||
|
}
|
||||||
|
template<class L, class R, typename std::enable_if<rexy::detail::is_concrete_string<L>::value && rexy::detail::is_binary_type<R>::value,void>::type* = nullptr>
|
||||||
|
decltype(auto) operator+=(L& l, R&& r){
|
||||||
|
l.resize(l.length(), r.size() + 1);
|
||||||
|
memcpy(l.get()+l.length()+1, r.get(), r.size());
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
48
rexy/detail/default_allocator.hpp
Normal file
48
rexy/detail/default_allocator.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_DEFAULT_ALLOCATOR_HPP
|
||||||
|
#define REXY_DEFAULT_ALLOCATOR_HPP
|
||||||
|
|
||||||
|
#include <cstdlib> //size_t
|
||||||
|
#include <cstring> //memcpy
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
|
||||||
|
template<size_t Alignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__>
|
||||||
|
struct default_allocator
|
||||||
|
{
|
||||||
|
static void free(void* data){
|
||||||
|
::operator delete(data, std::align_val_t{Alignment});
|
||||||
|
}
|
||||||
|
static void* allocate(size_t size){
|
||||||
|
return ::operator new(size, std::align_val_t{Alignment});
|
||||||
|
}
|
||||||
|
static void* copy(const void* c, size_t size){
|
||||||
|
char* tmp = reinterpret_cast<char*>(allocate(size));
|
||||||
|
memcpy(tmp, c, size);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
112
rexy/filerd.cpp
Normal file
112
rexy/filerd.cpp
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "filerd.hpp"
|
||||||
|
|
||||||
|
#include <cstdio> //fopen, fclose
|
||||||
|
#include <utility> //exchange, swap
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
filerd::filerd(const char* f, const char* mode):
|
||||||
|
m_fp(fopen(f, mode)){}
|
||||||
|
filerd::filerd(filerd&& f):
|
||||||
|
m_fp(std::exchange(f.m_fp, nullptr)){}
|
||||||
|
filerd::~filerd(void){
|
||||||
|
if(m_fp)
|
||||||
|
fclose(m_fp);
|
||||||
|
}
|
||||||
|
filerd& filerd::operator=(filerd&& f){
|
||||||
|
std::swap(m_fp, f.m_fp);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filerd::reset(FILE* fp){
|
||||||
|
if(m_fp)
|
||||||
|
fclose(m_fp);
|
||||||
|
m_fp = fp;
|
||||||
|
}
|
||||||
|
FILE* filerd::release(void){
|
||||||
|
return std::exchange(m_fp, nullptr);
|
||||||
|
}
|
||||||
|
size_t filerd::length(void){
|
||||||
|
if(!m_fp)
|
||||||
|
return 0;
|
||||||
|
size_t tmp, ret;
|
||||||
|
tmp = ftell(m_fp);
|
||||||
|
fseek(m_fp, 0, SEEK_END);
|
||||||
|
ret = ftell(m_fp);
|
||||||
|
fseek(m_fp, tmp, SEEK_SET);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
size_t filerd::position(void)const{
|
||||||
|
return ftell(m_fp);
|
||||||
|
}
|
||||||
|
void filerd::rewind(size_t pos){
|
||||||
|
fseek(m_fp, pos, SEEK_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
filerd::operator FILE*(void){
|
||||||
|
return m_fp;
|
||||||
|
}
|
||||||
|
filerd::operator const FILE*(void)const{
|
||||||
|
return m_fp;
|
||||||
|
}
|
||||||
|
FILE* filerd::get(void){
|
||||||
|
return m_fp;
|
||||||
|
}
|
||||||
|
const FILE* filerd::get(void)const{
|
||||||
|
return m_fp;
|
||||||
|
}
|
||||||
|
filerd::operator bool(void)const{
|
||||||
|
return m_fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t filerd::read(char* dest, size_t bytes){
|
||||||
|
return fread(dest, 1, bytes, m_fp);
|
||||||
|
}
|
||||||
|
rexy::string filerd::read(size_t bytes){
|
||||||
|
char* tmp = reinterpret_cast<char*>(rexy::string::allocator_type::allocate(bytes));
|
||||||
|
size_t written = read(tmp, bytes);
|
||||||
|
return rexy::string(tmp, written);
|
||||||
|
}
|
||||||
|
rexy::string filerd::readln(size_t max){
|
||||||
|
rexy::string ret;
|
||||||
|
char c;
|
||||||
|
size_t count = 0;
|
||||||
|
for(c = fgetc(m_fp);c != EOF && c != '\n';c = fgetc(m_fp)){
|
||||||
|
ret.append(&c, 1);
|
||||||
|
if(++count == max)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
rexy::binary filerd::read_bin(size_t bytes){
|
||||||
|
char* tmp = reinterpret_cast<char*>(rexy::binary::allocator_type::allocate(bytes));
|
||||||
|
size_t written = read(tmp, bytes);
|
||||||
|
return rexy::binary(tmp, written, written);
|
||||||
|
}
|
||||||
|
size_t filerd::write(const char* c, size_t bytes){
|
||||||
|
return fwrite(c, 1, bytes, m_fp);
|
||||||
|
}
|
||||||
|
size_t filerd::write(const rexy::string_base& c){
|
||||||
|
return write(c.get(), c.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
68
rexy/filerd.hpp
Normal file
68
rexy/filerd.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_FILERD_HPP
|
||||||
|
#define REXY_FILERD_HPP
|
||||||
|
|
||||||
|
#include <cstdio> //FILE
|
||||||
|
#include <cstddef> //size_t
|
||||||
|
|
||||||
|
#include <rexy/string.hpp>
|
||||||
|
#include <rexy/binary.hpp>
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
//RAII wrapper for FILE*
|
||||||
|
class filerd
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
FILE* m_fp = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
filerd(void) = default;
|
||||||
|
filerd(const char* f, const char* mode = "r");
|
||||||
|
filerd(const filerd&) = delete;
|
||||||
|
filerd(filerd&& f);
|
||||||
|
~filerd(void);
|
||||||
|
filerd& operator=(const filerd&) = delete;
|
||||||
|
filerd& operator=(filerd&& f);
|
||||||
|
|
||||||
|
void reset(FILE* fp = nullptr);
|
||||||
|
FILE* release(void);
|
||||||
|
size_t length(void);
|
||||||
|
size_t position(void)const;
|
||||||
|
void rewind(size_t pos = 0);
|
||||||
|
|
||||||
|
operator FILE*(void);
|
||||||
|
operator const FILE*(void)const;
|
||||||
|
FILE* get(void);
|
||||||
|
const FILE* get(void)const;
|
||||||
|
operator bool(void)const;
|
||||||
|
|
||||||
|
size_t read(char* dest, size_t bytes);
|
||||||
|
rexy::string read(size_t bytes);
|
||||||
|
rexy::string readln(size_t max = 0);
|
||||||
|
rexy::binary read_bin(size_t bytes);
|
||||||
|
|
||||||
|
size_t write(const char* c, size_t bytes);
|
||||||
|
size_t write(const rexy::string_base&);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
32
rexy/string.hpp
Normal file
32
rexy/string.hpp
Normal 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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_STRING_HPP
|
||||||
|
#define REXY_STRING_HPP
|
||||||
|
|
||||||
|
#include <rexy/string_base.hpp>
|
||||||
|
#include <rexy/detail/default_allocator.hpp>
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
//new allocated string
|
||||||
|
using string = string_intermediary<detail::default_allocator<>>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
49
rexy/string_base.cpp
Normal file
49
rexy/string_base.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "string_base.hpp"
|
||||||
|
|
||||||
|
#include <utility> //exchange, swap
|
||||||
|
#include <cstdlib> //memcpy
|
||||||
|
#include <cstring> //strcpy, strlen
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
char* string_base::release(void){
|
||||||
|
return std::exchange(m_data, nullptr);
|
||||||
|
}
|
||||||
|
char& string_base::operator[](size_t i){
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
const char& string_base::operator[](size_t i)const{
|
||||||
|
return m_data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static_string::static_string(const char* c):
|
||||||
|
static_string(const_cast<char*>(c), strlen(c)){}
|
||||||
|
static_string& static_string::operator=(const char* c){
|
||||||
|
m_data = const_cast<char*>(c);
|
||||||
|
m_length = strlen(c);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
static_string& static_string::operator=(const static_string& s){
|
||||||
|
m_data = s.m_data;
|
||||||
|
m_length = s.m_length;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
294
rexy/string_base.hpp
Normal file
294
rexy/string_base.hpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_STRING_BASE_HPP
|
||||||
|
#define REXY_STRING_BASE_HPP
|
||||||
|
|
||||||
|
#include <type_traits> //is_same, integral_contant, enable_if, etc
|
||||||
|
#include <utility> //forward
|
||||||
|
#include <cstdlib> //size_t
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
|
||||||
|
class string_expr{};
|
||||||
|
|
||||||
|
//Base of all RAII strings. Its use is allowing passing of rexy strings to functions without knowing the exact type
|
||||||
|
class string_base : public string_expr
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
size_t m_length = 0;
|
||||||
|
size_t m_cap = 0;
|
||||||
|
char* m_data = nullptr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
constexpr string_base(void) = default;
|
||||||
|
constexpr string_base(size_t len):
|
||||||
|
m_cap(len){}
|
||||||
|
//Initialize without copying
|
||||||
|
constexpr string_base(char* data, size_t len):
|
||||||
|
m_cap(len), m_data(data){}
|
||||||
|
constexpr string_base(char* data, size_t len, size_t cap):
|
||||||
|
m_length(len), m_cap(cap), m_data(data){}
|
||||||
|
//Copy ctor (do nothing)
|
||||||
|
string_base(const string_base&){}
|
||||||
|
~string_base(void) = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Stop managing stored pointer. Does not free.
|
||||||
|
char* release(void);
|
||||||
|
|
||||||
|
//Length of string not including null terminator
|
||||||
|
constexpr size_t length(void)const{return m_length;}
|
||||||
|
constexpr size_t capacity(void)const{return m_cap;}
|
||||||
|
//direct access to managed pointer
|
||||||
|
constexpr char* get(void){return m_data;}
|
||||||
|
constexpr const char* get(void)const{return m_data;}
|
||||||
|
constexpr operator char*(void){return m_data;}
|
||||||
|
constexpr operator const char*(void)const{return m_data;}
|
||||||
|
//true if m_data is not null
|
||||||
|
constexpr operator bool(void)const{return m_data;}
|
||||||
|
|
||||||
|
char& operator[](size_t i);
|
||||||
|
const char& operator[](size_t i)const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Supplies all functions that string_base can't implement
|
||||||
|
template<class Allocator>
|
||||||
|
class string_intermediary : public string_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using allocator_type = Allocator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string_intermediary(void) = default;
|
||||||
|
string_intermediary(char* data, size_t len);
|
||||||
|
string_intermediary(const char* data, size_t len);
|
||||||
|
string_intermediary(char* data, size_t len, size_t cap);
|
||||||
|
string_intermediary(const char* data);
|
||||||
|
string_intermediary(size_t len);
|
||||||
|
string_intermediary(size_t len, size_t cap);
|
||||||
|
|
||||||
|
//normal copy and move ctors
|
||||||
|
string_intermediary(const string_intermediary& b);
|
||||||
|
string_intermediary(string_intermediary&& s);
|
||||||
|
|
||||||
|
string_intermediary(const string_base& b);
|
||||||
|
|
||||||
|
//dtor
|
||||||
|
~string_intermediary(void);
|
||||||
|
|
||||||
|
string_intermediary& operator=(const string_intermediary& s);
|
||||||
|
string_intermediary& operator=(string_intermediary&& s);
|
||||||
|
//Copy from c string
|
||||||
|
string_intermediary& operator=(const char* c);
|
||||||
|
//Copy from other string_base
|
||||||
|
string_intermediary& operator=(const string_base& s);
|
||||||
|
|
||||||
|
//Replace managed pointer. Frees existing value
|
||||||
|
void reset(char* val = nullptr);
|
||||||
|
void reset(char* val, size_t len);
|
||||||
|
bool resize(size_t newsize);
|
||||||
|
void append(const char* data, size_t len);
|
||||||
|
void append(const char* data);
|
||||||
|
void append(const string_base& s);
|
||||||
|
|
||||||
|
private:
|
||||||
|
string_intermediary& _copy_string(const char* s, size_t len);
|
||||||
|
};
|
||||||
|
|
||||||
|
//Like an expression template but not really
|
||||||
|
template<class Left, class Right>
|
||||||
|
class string_cat_expr : public string_expr
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Left m_l;
|
||||||
|
Right m_r;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class T, class U>
|
||||||
|
constexpr string_cat_expr(T&& l, U&& r);
|
||||||
|
constexpr string_cat_expr(const string_cat_expr& s);
|
||||||
|
constexpr string_cat_expr(string_cat_expr&& s);
|
||||||
|
|
||||||
|
constexpr size_t length(void)const;
|
||||||
|
template<class Alloc>
|
||||||
|
operator string_intermediary<Alloc>(void);
|
||||||
|
constexpr const Left& left(void)const;
|
||||||
|
constexpr const Right& right(void)const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class static_string : public string_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr static_string(void) = default;
|
||||||
|
template<size_t N>
|
||||||
|
constexpr static_string(const char(&str)[N]);
|
||||||
|
constexpr static_string(const char* str, size_t len);
|
||||||
|
static_string(const char* c);
|
||||||
|
constexpr static_string(const static_string& s);
|
||||||
|
constexpr static_string(static_string&& s);
|
||||||
|
~static_string(void) = default;
|
||||||
|
|
||||||
|
static_string& operator=(const char* c);
|
||||||
|
static_string& operator=(const static_string& s);
|
||||||
|
static_string& operator=(static_string&&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
std::true_type is_string_helper(string_expr);
|
||||||
|
std::false_type is_string_helper(...);
|
||||||
|
template<class T>
|
||||||
|
struct is_string{
|
||||||
|
static constexpr bool value = std::is_same<std::true_type,decltype(is_string_helper(std::declval<T>()))>::value;
|
||||||
|
};
|
||||||
|
std::true_type is_string_base(string_base*);
|
||||||
|
std::false_type is_string_base(...);
|
||||||
|
template<class T>
|
||||||
|
struct is_concrete_string{
|
||||||
|
static constexpr bool value = std::is_same<std::true_type,decltype(is_string_base(std::declval<typename std::decay<T>::type*>()))>::value;
|
||||||
|
};
|
||||||
|
template<class... Args>
|
||||||
|
std::true_type is_tuple_helper(std::tuple<Args...>);
|
||||||
|
std::false_type is_tuple_helper(...);
|
||||||
|
template<class T>
|
||||||
|
struct is_tuple{
|
||||||
|
static constexpr bool value = std::is_same<std::true_type,decltype(is_tuple_helper(std::declval<T>()))>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//check for member function 'length'
|
||||||
|
template<class T>
|
||||||
|
struct has_len{
|
||||||
|
template<class U, class V>
|
||||||
|
struct check;
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
static std::true_type test(check<U,decltype(&U::length)>*);
|
||||||
|
template<class U>
|
||||||
|
static std::false_type test(...);
|
||||||
|
|
||||||
|
static constexpr bool value = std::is_same<std::true_type,decltype(test<T>(0))>::value;
|
||||||
|
};
|
||||||
|
template<class Targ>
|
||||||
|
struct appender
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Targ& m_targ;
|
||||||
|
public:
|
||||||
|
appender(Targ& t);
|
||||||
|
template<class L, class R>
|
||||||
|
void operator()(const string_cat_expr<L,R>& str);
|
||||||
|
void operator()(const string_base& str);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <rexy/string_base.tpp>
|
||||||
|
|
||||||
|
namespace{
|
||||||
|
constexpr inline rexy::static_string operator"" _ss(const char* str, size_t len){
|
||||||
|
return rexy::static_string(str, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Str1, class Str2, typename std::enable_if<rexy::detail::is_concrete_string<Str1>::value&&rexy::detail::is_concrete_string<Str2>::value,void>::type* = nullptr>
|
||||||
|
bool operator==(Str1&& left, Str2&& right){
|
||||||
|
return left && right && left.length() == right.length() && !strcmp(left.get(), right.get());
|
||||||
|
}
|
||||||
|
template<class Str1, class Str2, typename std::enable_if<rexy::detail::is_concrete_string<Str1>::value&&rexy::detail::is_concrete_string<Str2>::value,void>::type* = nullptr>
|
||||||
|
bool operator!=(Str1&& left, Str2&& right){
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Right, typename std::enable_if<rexy::detail::is_string<Right>::value && std::is_rvalue_reference<Right&&>::value,void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(const char* left, Right&& right){
|
||||||
|
return rexy::string_cat_expr<rexy::static_string,typename std::remove_reference<Right>::type>(rexy::static_string(left), std::move(right));
|
||||||
|
}
|
||||||
|
template<class Right, typename std::enable_if<rexy::detail::is_string<Right>::value && !std::is_rvalue_reference<Right&&>::value,void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(const char* left, Right&& right){
|
||||||
|
return rexy::string_cat_expr<rexy::static_string,decltype(std::forward<Right>(right))>(rexy::static_string(left), std::forward<Right>(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Left, typename std::enable_if<rexy::detail::is_string<Left>::value && std::is_rvalue_reference<Left&&>::value,void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& left, const char* right){
|
||||||
|
return rexy::string_cat_expr<typename std::remove_reference<Left>::type,rexy::static_string>(std::move(left), rexy::static_string(right));
|
||||||
|
}
|
||||||
|
template<class Left, typename std::enable_if<rexy::detail::is_string<Left>::value && !std::is_rvalue_reference<Left&&>::value,void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& left, const char* right){
|
||||||
|
return rexy::string_cat_expr<decltype(std::forward<Left>(left)),rexy::static_string>(std::forward<Left>(left), rexy::static_string(right));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Left,
|
||||||
|
class Right,
|
||||||
|
typename std::enable_if<
|
||||||
|
rexy::detail::is_string<Left>::value &&
|
||||||
|
rexy::detail::is_string<Right>::value &&
|
||||||
|
std::is_rvalue_reference<Left&&>::value &&
|
||||||
|
std::is_rvalue_reference<Right&&>::value,
|
||||||
|
void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& l, Right&& r){
|
||||||
|
return rexy::string_cat_expr<typename std::remove_reference<Left>::type,typename std::remove_reference<Right>::type>(std::move(l), std::move(r));
|
||||||
|
}
|
||||||
|
template<class Left,
|
||||||
|
class Right,
|
||||||
|
typename std::enable_if<
|
||||||
|
rexy::detail::is_string<Left>::value &&
|
||||||
|
rexy::detail::is_string<Right>::value &&
|
||||||
|
!std::is_rvalue_reference<Left&&>::value &&
|
||||||
|
!std::is_rvalue_reference<Right&&>::value,
|
||||||
|
void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& l, Right&& r){
|
||||||
|
return rexy::string_cat_expr<decltype(std::forward<Left>(l)),decltype(std::forward<Right>(r))>(std::forward<Left>(l), std::forward<Right>(r));
|
||||||
|
}
|
||||||
|
template<class Left,
|
||||||
|
class Right,
|
||||||
|
typename std::enable_if<
|
||||||
|
rexy::detail::is_string<Left>::value &&
|
||||||
|
rexy::detail::is_string<Right>::value &&
|
||||||
|
std::is_rvalue_reference<Left&&>::value &&
|
||||||
|
!std::is_rvalue_reference<Right&&>::value,
|
||||||
|
void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& l, Right&& r){
|
||||||
|
return rexy::string_cat_expr<typename std::remove_reference<Left>::type,decltype(std::forward<Right>(r))>(std::move(l), std::forward<Right>(r));
|
||||||
|
}
|
||||||
|
template<class Left,
|
||||||
|
class Right,
|
||||||
|
typename std::enable_if<
|
||||||
|
rexy::detail::is_string<Left>::value &&
|
||||||
|
rexy::detail::is_string<Right>::value &&
|
||||||
|
!std::is_rvalue_reference<Left&&>::value &&
|
||||||
|
std::is_rvalue_reference<Right&&>::value,
|
||||||
|
void>::type* = nullptr>
|
||||||
|
constexpr auto operator+(Left&& l, Right&& r){
|
||||||
|
return rexy::string_cat_expr<decltype(std::forward<Left>(l)),typename std::remove_reference<Right>::type>(std::forward<Left>(l), std::move(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Left, class Right, typename std::enable_if<rexy::detail::is_string<Left>::value&&rexy::detail::is_string<Right>::value,void>::type* = nullptr>
|
||||||
|
decltype(auto) operator+=(Left& l, Right&& r){
|
||||||
|
return l = (l + std::forward<Right>(r));
|
||||||
|
}
|
||||||
|
template<class Left, typename std::enable_if<rexy::detail::is_string<Left>::value,void>::type* = nullptr>
|
||||||
|
decltype(auto) operator+=(Left& l, const char* r){
|
||||||
|
return l = (l + r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef REXY_BINARY_HPP
|
||||||
|
#include <rexy/detail/binary_string_conv.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
247
rexy/string_base.tpp
Normal file
247
rexy/string_base.tpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
/**
|
||||||
|
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 Affero 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef REXY_STRING_BASE_TPP
|
||||||
|
#define REXY_STRING_BASE_TPP
|
||||||
|
|
||||||
|
#include <utility> //forward, move, swap, etc
|
||||||
|
#include <cstdlib> //memcpy
|
||||||
|
#include <cstring> //strlen, strcpy
|
||||||
|
#include <algorithm> //max
|
||||||
|
|
||||||
|
namespace rexy{
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(char* data, size_t len):
|
||||||
|
string_base(data, len){}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(char* data, size_t len, size_t cap):
|
||||||
|
string_base(data, len, cap){}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(const char* data, size_t len):
|
||||||
|
string_base(reinterpret_cast<char*>(len ? Allocator::copy(data, len+1) : nullptr), len)
|
||||||
|
{
|
||||||
|
m_data[len] = 0;
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(const char* data):
|
||||||
|
string_base(data ? strlen(data) : 0)
|
||||||
|
{
|
||||||
|
if(m_cap){
|
||||||
|
m_data = reinterpret_cast<char*>(Allocator::copy(data, m_cap+1));
|
||||||
|
m_length = m_cap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(size_t len):
|
||||||
|
string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len)
|
||||||
|
{
|
||||||
|
m_data[len] = 0;
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(size_t len, size_t cap):
|
||||||
|
string_base(reinterpret_cast<char*>(len ? Allocator::allocate(len+1) : nullptr), len, cap)
|
||||||
|
{
|
||||||
|
m_data[len] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//normal copy and move ctors
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(const string_intermediary& b):
|
||||||
|
string_base(reinterpret_cast<char*>(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(string_intermediary&& s):
|
||||||
|
string_base(std::exchange(s.m_data, nullptr), s.m_length, s.m_cap){}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::string_intermediary(const string_base& b):
|
||||||
|
string_base(reinterpret_cast<char*>(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){}
|
||||||
|
|
||||||
|
//dtor
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>::~string_intermediary(void){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_intermediary& s){
|
||||||
|
if(s.m_length < m_length){
|
||||||
|
memcpy(m_data, s.m_data, s.m_length+1);
|
||||||
|
m_length = s.m_length;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
string_intermediary tmp(s);
|
||||||
|
return (*this = std::move(tmp));
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(string_intermediary&& s){
|
||||||
|
std::swap(m_data, s.m_data);
|
||||||
|
m_length = s.m_length;
|
||||||
|
m_cap = s.m_cap;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
//Copy from c string
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const char* c){
|
||||||
|
return _copy_string(c, strlen(c));
|
||||||
|
}
|
||||||
|
//Copy from other string_base
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>& string_intermediary<Allocator>::operator=(const string_base& s){
|
||||||
|
return _copy_string(s.get(), s.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Replace managed pointer. Frees existing value
|
||||||
|
template<class Allocator>
|
||||||
|
void string_intermediary<Allocator>::reset(char* val){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_data = val;
|
||||||
|
m_length = val ? strlen(val) : 0;
|
||||||
|
m_cap = m_length;
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
void string_intermediary<Allocator>::reset(char* val, size_t len){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_data = val;
|
||||||
|
m_length = len;
|
||||||
|
m_cap = len;
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
bool string_intermediary<Allocator>::resize(size_t newsize){
|
||||||
|
if(newsize < m_cap)
|
||||||
|
return false;
|
||||||
|
string_intermediary tmp(newsize);
|
||||||
|
memcpy(tmp.get(), m_data, m_length);
|
||||||
|
tmp[m_length] = 0;
|
||||||
|
*this = std::move(tmp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
void string_intermediary<Allocator>::append(const char* data, size_t len){
|
||||||
|
if(len+m_length <= m_cap){
|
||||||
|
memcpy(m_data+m_length, data, len);
|
||||||
|
m_length += len;
|
||||||
|
m_data[m_length] = 0;
|
||||||
|
}else{
|
||||||
|
string_intermediary tmp(std::max(m_length + len, m_cap*2));
|
||||||
|
memcpy(tmp.m_data, m_data, m_length);
|
||||||
|
memcpy(tmp.m_data+m_length, data, len);
|
||||||
|
tmp.m_length = len+m_length;
|
||||||
|
tmp[m_length+len] = 0;
|
||||||
|
*this = std::move(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
void string_intermediary<Allocator>::append(const char* data){
|
||||||
|
if(data)
|
||||||
|
append(data, strlen(data));
|
||||||
|
}
|
||||||
|
template<class Allocator>
|
||||||
|
void string_intermediary<Allocator>::append(const string_base& s){
|
||||||
|
append(s.get(), s.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Allocator>
|
||||||
|
string_intermediary<Allocator>& string_intermediary<Allocator>::_copy_string(const char* s, size_t len){
|
||||||
|
if(!len){
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_length = 0;
|
||||||
|
m_cap = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
if(len <= m_length){
|
||||||
|
strcpy(m_data, s);
|
||||||
|
}else{
|
||||||
|
Allocator::free(m_data);
|
||||||
|
m_cap = std::max(len, m_cap*2);
|
||||||
|
m_data = reinterpret_cast<char*>(Allocator::copy(s, m_cap+1));
|
||||||
|
if(!m_data){
|
||||||
|
m_length = 0;
|
||||||
|
m_cap = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_length = len;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Left, class Right>
|
||||||
|
template<class T, class U>
|
||||||
|
constexpr string_cat_expr<Left,Right>::string_cat_expr(T&& l, U&& r):
|
||||||
|
m_l(std::forward<T>(l)),
|
||||||
|
m_r(std::forward<U>(r)){}
|
||||||
|
template<class Left, class Right>
|
||||||
|
constexpr string_cat_expr<Left,Right>::string_cat_expr(const string_cat_expr& s):
|
||||||
|
m_l(std::forward<Left>(s.m_l)),
|
||||||
|
m_r(std::forward<Right>(s.m_r)){}
|
||||||
|
template<class Left, class Right>
|
||||||
|
constexpr string_cat_expr<Left,Right>::string_cat_expr(string_cat_expr&& s):
|
||||||
|
m_l(std::forward<Left>(s.m_l)),
|
||||||
|
m_r(std::forward<Right>(s.m_r)){}
|
||||||
|
|
||||||
|
template<class Left, class Right>
|
||||||
|
constexpr size_t string_cat_expr<Left,Right>::length(void)const{
|
||||||
|
return m_l.length() + m_r.length();
|
||||||
|
}
|
||||||
|
template<class Left, class Right>
|
||||||
|
template<class Alloc>
|
||||||
|
string_cat_expr<Left,Right>::operator string_intermediary<Alloc>(void){
|
||||||
|
size_t len = length();
|
||||||
|
string_intermediary<Alloc> ret(len);
|
||||||
|
detail::appender<string_intermediary<Alloc>> append(ret);
|
||||||
|
append(*this);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
template<class Left, class Right>
|
||||||
|
constexpr const Left& string_cat_expr<Left,Right>::left(void)const{
|
||||||
|
return m_l;
|
||||||
|
}
|
||||||
|
template<class Left, class Right>
|
||||||
|
constexpr const Right& string_cat_expr<Left,Right>::right(void)const{
|
||||||
|
return m_r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
constexpr static_string::static_string(const char(&str)[N]):
|
||||||
|
string_base(const_cast<char*>(str), N, N){}
|
||||||
|
constexpr static_string::static_string(const char* str, size_t len):
|
||||||
|
string_base(const_cast<char*>(str), len, len){}
|
||||||
|
constexpr static_string::static_string(const static_string& s):
|
||||||
|
string_base(s.m_data, s.m_length, s.m_length){}
|
||||||
|
constexpr static_string::static_string(static_string&& s):
|
||||||
|
string_base(s.m_data, s.m_length, s.m_length){}
|
||||||
|
|
||||||
|
namespace detail{
|
||||||
|
template<class Targ>
|
||||||
|
appender<Targ>::appender(Targ& t): m_targ(t){}
|
||||||
|
template<class Targ>
|
||||||
|
template<class L, class R>
|
||||||
|
void appender<Targ>::operator()(const string_cat_expr<L,R>& str){
|
||||||
|
(*this)(str.left());
|
||||||
|
(*this)(str.right());
|
||||||
|
}
|
||||||
|
template<class Targ>
|
||||||
|
void appender<Targ>::operator()(const string_base& str){
|
||||||
|
m_targ.append(str.get(), str.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace rexy
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
x
Reference in New Issue
Block a user