commit 066d875f913310721446baf54b2fc80474632ae1 Author: rexy712 Date: Mon Mar 2 16:35:52 2020 -0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7446455 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +tester +lib*.a +lib*.so +build +*.swp +obj +*.o +*.d +test.cpp +tester.cpp diff --git a/makefile b/makefile new file mode 100644 index 0000000..ff3d3fd --- /dev/null +++ b/makefile @@ -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 . + +#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) + diff --git a/rexy/binary.cpp b/rexy/binary.cpp new file mode 100644 index 0000000..4cb340f --- /dev/null +++ b/rexy/binary.cpp @@ -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 . +*/ + +#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]; + } +} diff --git a/rexy/binary.hpp b/rexy/binary.hpp new file mode 100644 index 0000000..87ee3a7 --- /dev/null +++ b/rexy/binary.hpp @@ -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 . +*/ + +#ifndef REXY_BINARY_HPP +#define REXY_BINARY_HPP + +#include //size_t +#include //move +#include //memcpy +#include //max +#include +#include +#include + +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 + 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 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(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(Allocator::copy(data, size)), cap, size){} + binary_data(size_t size): + binary_base(reinterpret_cast(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 + struct is_binary_type{ + constexpr static bool value = std::is_same::type>())),std::true_type>::value; + }; + } + +} + +template::value && rexy::detail::is_binary_type::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::value && rexy::detail::is_binary_type::value,void>::type* = nullptr> +bool operator!=(Left&& l, Right&& r){ + return !(std::forward(l) == std::forward(r)); +} +template +auto operator+(const rexy::binary_data& l, const rexy::binary_data& r){ + rexy::binary_data retval(l.size() + r.size()); + memcpy(retval.get(), l.get(), l.size()); + memcpy(retval.get()+l.size(), r.get(), r.size()); + return retval; +} +template +decltype(auto) operator+=(rexy::binary_data& l, const rexy::binary_data& r){ + l.resize(l.size() + r.size()); + memcpy(l.get()+l.size(), r.get(), r.size()); + return l; +} + +#ifdef REXY_STRING_BASE_HPP +#include +#endif + +#endif diff --git a/rexy/detail/binary_string_conv.hpp b/rexy/detail/binary_string_conv.hpp new file mode 100644 index 0000000..ec8a401 --- /dev/null +++ b/rexy/detail/binary_string_conv.hpp @@ -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 . +*/ + +#ifndef REXY_BINARY_STRING_CONV_HPP +#define REXY_BINARY_STRING_CONV_HPP + +#include +#include + +namespace rexy{ + template::value,void>::type* = nullptr> + auto binary_to_string(const binary_data& b){ + Str s(b.size()+1); + memcpy(s.get(), b.get(), b.size()); + s[b.size()] = 0; + return s; + } + template::value && std::is_same::type,typename Str::allocator_type>::value,void>::type* = nullptr> + auto binary_to_string(binary_data&& b){ + Str s; + s.reset(b.get(), b.size()); + b.release(); + return s; + } + template::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::value && std::is_same::type,typename Bin::allocator_type>::value,void>::type* = nullptr> + auto string_to_binary(string_intermediary&& s){ + Bin b; + b.reset(s.get(), s.length()+1); + s.release(); + return b; + } +} +template::value && rexy::detail::is_concrete_string::value,void>::type* = nullptr> +decltype(auto) operator+=(L& l, R&& r){ + l.append(r.get(), r.length()+1); + return l; +} +template::value && rexy::detail::is_string::value && !rexy::detail::is_concrete_string::value,void>::type* = nullptr> +decltype(auto) operator+=(L& l, R&& r){ + rexy::string concrete = r; + return (l = concrete); +} +template::value && rexy::detail::is_binary_type::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 diff --git a/rexy/detail/default_allocator.hpp b/rexy/detail/default_allocator.hpp new file mode 100644 index 0000000..c659622 --- /dev/null +++ b/rexy/detail/default_allocator.hpp @@ -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 . +*/ + +#ifndef REXY_DEFAULT_ALLOCATOR_HPP +#define REXY_DEFAULT_ALLOCATOR_HPP + +#include //size_t +#include //memcpy +#include + +namespace rexy{ + + namespace detail{ + + template + 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(allocate(size)); + memcpy(tmp, c, size); + return tmp; + } + }; + } +} + +#endif diff --git a/rexy/filerd.cpp b/rexy/filerd.cpp new file mode 100644 index 0000000..bd5ed0b --- /dev/null +++ b/rexy/filerd.cpp @@ -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 . +*/ + +#include "filerd.hpp" + +#include //fopen, fclose +#include //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(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(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()); + } + +} + diff --git a/rexy/filerd.hpp b/rexy/filerd.hpp new file mode 100644 index 0000000..dd1deec --- /dev/null +++ b/rexy/filerd.hpp @@ -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 . +*/ + +#ifndef REXY_FILERD_HPP +#define REXY_FILERD_HPP + +#include //FILE +#include //size_t + +#include +#include + +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 diff --git a/rexy/string.hpp b/rexy/string.hpp new file mode 100644 index 0000000..b90e658 --- /dev/null +++ b/rexy/string.hpp @@ -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 . +*/ + +#ifndef REXY_STRING_HPP +#define REXY_STRING_HPP + +#include +#include + +namespace rexy{ + + //new allocated string + using string = string_intermediary>; + +} + +#endif diff --git a/rexy/string_base.cpp b/rexy/string_base.cpp new file mode 100644 index 0000000..d03b04c --- /dev/null +++ b/rexy/string_base.cpp @@ -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 . +*/ + +#include "string_base.hpp" + +#include //exchange, swap +#include //memcpy +#include //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(c), strlen(c)){} + static_string& static_string::operator=(const char* c){ + m_data = const_cast(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; + } + +} diff --git a/rexy/string_base.hpp b/rexy/string_base.hpp new file mode 100644 index 0000000..ef11bb3 --- /dev/null +++ b/rexy/string_base.hpp @@ -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 . +*/ + +#ifndef REXY_STRING_BASE_HPP +#define REXY_STRING_BASE_HPP + +#include //is_same, integral_contant, enable_if, etc +#include //forward +#include //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 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 string_cat_expr : public string_expr + { + private: + Left m_l; + Right m_r; + + public: + template + 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 + operator string_intermediary(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 + 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 + struct is_string{ + static constexpr bool value = std::is_same()))>::value; + }; + std::true_type is_string_base(string_base*); + std::false_type is_string_base(...); + template + struct is_concrete_string{ + static constexpr bool value = std::is_same::type*>()))>::value; + }; + template + std::true_type is_tuple_helper(std::tuple); + std::false_type is_tuple_helper(...); + template + struct is_tuple{ + static constexpr bool value = std::is_same()))>::value; + }; + + //check for member function 'length' + template + struct has_len{ + template + struct check; + + template + static std::true_type test(check*); + template + static std::false_type test(...); + + static constexpr bool value = std::is_same(0))>::value; + }; + template + struct appender + { + private: + Targ& m_targ; + public: + appender(Targ& t); + template + void operator()(const string_cat_expr& str); + void operator()(const string_base& str); + }; + } +} + +#include + +namespace{ + constexpr inline rexy::static_string operator"" _ss(const char* str, size_t len){ + return rexy::static_string(str, len); + } +} +template::value&&rexy::detail::is_concrete_string::value,void>::type* = nullptr> +bool operator==(Str1&& left, Str2&& right){ + return left && right && left.length() == right.length() && !strcmp(left.get(), right.get()); +} +template::value&&rexy::detail::is_concrete_string::value,void>::type* = nullptr> +bool operator!=(Str1&& left, Str2&& right){ + return !(left == right); +} + +template::value && std::is_rvalue_reference::value,void>::type* = nullptr> +constexpr auto operator+(const char* left, Right&& right){ + return rexy::string_cat_expr::type>(rexy::static_string(left), std::move(right)); +} +template::value && !std::is_rvalue_reference::value,void>::type* = nullptr> +constexpr auto operator+(const char* left, Right&& right){ + return rexy::string_cat_expr(right))>(rexy::static_string(left), std::forward(right)); +} + +template::value && std::is_rvalue_reference::value,void>::type* = nullptr> +constexpr auto operator+(Left&& left, const char* right){ + return rexy::string_cat_expr::type,rexy::static_string>(std::move(left), rexy::static_string(right)); +} +template::value && !std::is_rvalue_reference::value,void>::type* = nullptr> +constexpr auto operator+(Left&& left, const char* right){ + return rexy::string_cat_expr(left)),rexy::static_string>(std::forward(left), rexy::static_string(right)); +} + +template::value && + rexy::detail::is_string::value && + std::is_rvalue_reference::value && + std::is_rvalue_reference::value, + void>::type* = nullptr> +constexpr auto operator+(Left&& l, Right&& r){ + return rexy::string_cat_expr::type,typename std::remove_reference::type>(std::move(l), std::move(r)); +} +template::value && + rexy::detail::is_string::value && + !std::is_rvalue_reference::value && + !std::is_rvalue_reference::value, + void>::type* = nullptr> +constexpr auto operator+(Left&& l, Right&& r){ + return rexy::string_cat_expr(l)),decltype(std::forward(r))>(std::forward(l), std::forward(r)); +} +template::value && + rexy::detail::is_string::value && + std::is_rvalue_reference::value && + !std::is_rvalue_reference::value, + void>::type* = nullptr> +constexpr auto operator+(Left&& l, Right&& r){ + return rexy::string_cat_expr::type,decltype(std::forward(r))>(std::move(l), std::forward(r)); +} +template::value && + rexy::detail::is_string::value && + !std::is_rvalue_reference::value && + std::is_rvalue_reference::value, + void>::type* = nullptr> +constexpr auto operator+(Left&& l, Right&& r){ + return rexy::string_cat_expr(l)),typename std::remove_reference::type>(std::forward(l), std::move(r)); +} + +template::value&&rexy::detail::is_string::value,void>::type* = nullptr> +decltype(auto) operator+=(Left& l, Right&& r){ + return l = (l + std::forward(r)); +} +template::value,void>::type* = nullptr> +decltype(auto) operator+=(Left& l, const char* r){ + return l = (l + r); +} + +#ifdef REXY_BINARY_HPP +#include +#endif + +#endif diff --git a/rexy/string_base.tpp b/rexy/string_base.tpp new file mode 100644 index 0000000..bfa2b0f --- /dev/null +++ b/rexy/string_base.tpp @@ -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 . +*/ + +#ifndef REXY_STRING_BASE_TPP +#define REXY_STRING_BASE_TPP + +#include //forward, move, swap, etc +#include //memcpy +#include //strlen, strcpy +#include //max + +namespace rexy{ + template + string_intermediary::string_intermediary(char* data, size_t len): + string_base(data, len){} + template + string_intermediary::string_intermediary(char* data, size_t len, size_t cap): + string_base(data, len, cap){} + template + string_intermediary::string_intermediary(const char* data, size_t len): + string_base(reinterpret_cast(len ? Allocator::copy(data, len+1) : nullptr), len) + { + m_data[len] = 0; + } + template + string_intermediary::string_intermediary(const char* data): + string_base(data ? strlen(data) : 0) + { + if(m_cap){ + m_data = reinterpret_cast(Allocator::copy(data, m_cap+1)); + m_length = m_cap; + } + } + template + string_intermediary::string_intermediary(size_t len): + string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len) + { + m_data[len] = 0; + } + template + string_intermediary::string_intermediary(size_t len, size_t cap): + string_base(reinterpret_cast(len ? Allocator::allocate(len+1) : nullptr), len, cap) + { + m_data[len] = 0; + } + + //normal copy and move ctors + template + string_intermediary::string_intermediary(const string_intermediary& b): + string_base(reinterpret_cast(b.m_length ? Allocator::copy(b.m_data, b.m_length+1) : nullptr), b.m_length, b.m_cap){} + template + string_intermediary::string_intermediary(string_intermediary&& s): + string_base(std::exchange(s.m_data, nullptr), s.m_length, s.m_cap){} + + template + string_intermediary::string_intermediary(const string_base& b): + string_base(reinterpret_cast(b.length() ? Allocator::copy(b.get(), b.length()+1) : nullptr), b.length(), b.capacity()){} + + //dtor + template + string_intermediary::~string_intermediary(void){ + Allocator::free(m_data); + } + + template + string_intermediary& string_intermediary::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 + string_intermediary& string_intermediary::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 + string_intermediary& string_intermediary::operator=(const char* c){ + return _copy_string(c, strlen(c)); + } + //Copy from other string_base + template + string_intermediary& string_intermediary::operator=(const string_base& s){ + return _copy_string(s.get(), s.length()); + } + + //Replace managed pointer. Frees existing value + template + void string_intermediary::reset(char* val){ + Allocator::free(m_data); + m_data = val; + m_length = val ? strlen(val) : 0; + m_cap = m_length; + } + template + void string_intermediary::reset(char* val, size_t len){ + Allocator::free(m_data); + m_data = val; + m_length = len; + m_cap = len; + } + template + bool string_intermediary::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 + void string_intermediary::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 + void string_intermediary::append(const char* data){ + if(data) + append(data, strlen(data)); + } + template + void string_intermediary::append(const string_base& s){ + append(s.get(), s.length()); + } + + template + string_intermediary& string_intermediary::_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(Allocator::copy(s, m_cap+1)); + if(!m_data){ + m_length = 0; + m_cap = 0; + return *this; + } + } + m_length = len; + return *this; + } + + + template + template + constexpr string_cat_expr::string_cat_expr(T&& l, U&& r): + m_l(std::forward(l)), + m_r(std::forward(r)){} + template + constexpr string_cat_expr::string_cat_expr(const string_cat_expr& s): + m_l(std::forward(s.m_l)), + m_r(std::forward(s.m_r)){} + template + constexpr string_cat_expr::string_cat_expr(string_cat_expr&& s): + m_l(std::forward(s.m_l)), + m_r(std::forward(s.m_r)){} + + template + constexpr size_t string_cat_expr::length(void)const{ + return m_l.length() + m_r.length(); + } + template + template + string_cat_expr::operator string_intermediary(void){ + size_t len = length(); + string_intermediary ret(len); + detail::appender> append(ret); + append(*this); + return ret; + } + template + constexpr const Left& string_cat_expr::left(void)const{ + return m_l; + } + template + constexpr const Right& string_cat_expr::right(void)const{ + return m_r; + } + + + template + constexpr static_string::static_string(const char(&str)[N]): + string_base(const_cast(str), N, N){} + constexpr static_string::static_string(const char* str, size_t len): + string_base(const_cast(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 + appender::appender(Targ& t): m_targ(t){} + template + template + void appender::operator()(const string_cat_expr& str){ + (*this)(str.left()); + (*this)(str.right()); + } + template + void appender::operator()(const string_base& str){ + m_targ.append(str.get(), str.length()); + } + } + +} //namespace rexy + +#endif