Initial commit

This commit is contained in:
rexy712 2020-03-02 16:35:52 -08:00
commit 066d875f91
12 changed files with 1367 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
tester
lib*.a
lib*.so
build
*.swp
obj
*.o
*.d
test.cpp
tester.cpp

227
makefile Normal file
View 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
View 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
View 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

View 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

View 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
View 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
View 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
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 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
View 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
View 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
View 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