@@ -0,0 +1,7 @@ | |||||
# binaries | |||||
test/bin | |||||
#eclipse based files | |||||
.cproject | |||||
.project | |||||
.settings/ |
@@ -0,0 +1,48 @@ | |||||
/*! | |||||
* \file core/core.h | |||||
* | |||||
* \copyright Copyright (C) 2020-2021 Christos Choutouridis <christos@choutouridis.net> | |||||
* | |||||
* <dl class=\"section copyright\"><dt>License</dt><dd> | |||||
* The MIT License (MIT) | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in all | |||||
* copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
* SOFTWARE. | |||||
* </dd></dl> | |||||
*/ | |||||
#ifndef TBX_CORE_CORE_H_ | |||||
#define TBX_CORE_CORE_H_ | |||||
//#define __cplusplus 201703L // for developing puproses only | |||||
#include <cstddef> | |||||
#include <cstdint> | |||||
namespace tbx { | |||||
//! \name size and index | |||||
//! @{ | |||||
using size_t = std::size_t; | |||||
using index_t = size_t; //!< index_t and size_t mend to be interchangeable | |||||
using ptrdiff_t= std::ptrdiff_t; | |||||
//! @} | |||||
} | |||||
#endif /* TBX_CORE_CORE_H_ */ |
@@ -0,0 +1,55 @@ | |||||
/*! | |||||
* \file core/crtp.h | |||||
* \brief | |||||
* A CRTP idiom helper header | |||||
* | |||||
* \copyright Copyright (C) 2020 Christos Choutouridis <christos@choutouridis.net> | |||||
* | |||||
* <dl class=\"section copyright\"><dt>License</dt><dd> | |||||
* The MIT License (MIT) | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in all | |||||
* copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
* SOFTWARE. | |||||
* </dd></dl> | |||||
*/ | |||||
#ifndef TBX_CORE_CRTP_H_ | |||||
#define TBX_CORE_CRTP_H_ | |||||
/*! | |||||
* \defgroup crtp CRTP idiom support header | |||||
* | |||||
*/ | |||||
//!@{ | |||||
namespace tbx { | |||||
//! CRTP support tag type | |||||
struct crtp_tag { }; | |||||
//! virtual support tag type | |||||
struct virtual_tag { }; | |||||
//! \def CRTP boilerplate lines | |||||
#define _CRTP_IMPL(T) \ | |||||
constexpr T& impl() { return *static_cast<T*>(this); } \ | |||||
constexpr const T& impl() const { return *static_cast<const T*>(this); } | |||||
} | |||||
//!@} | |||||
#endif /* TBX_CORE_CRTP_H_ */ |
@@ -0,0 +1,227 @@ | |||||
/*! | |||||
* \file cont/ring_iterator.h | |||||
* \brief | |||||
* A ring/circular iterator. | |||||
* | |||||
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net> | |||||
* | |||||
* <dl class=\"section copyright\"><dt>License</dt><dd> | |||||
* The MIT License (MIT) | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in all | |||||
* copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
* SOFTWARE. | |||||
* </dd></dl> | |||||
*/ | |||||
#ifndef TBX_CORE_RING_ITERATOR_H_ | |||||
#define TBX_CORE_RING_ITERATOR_H_ | |||||
#include <core/core.h> | |||||
#include <iterator> | |||||
#include <type_traits> | |||||
namespace tbx { | |||||
template<typename Iter_t, size_t N> | |||||
class ring_iterator { | |||||
//! \name STL iterator traits "forwarding" | |||||
//! @{ | |||||
protected: | |||||
using traits_type = std::iterator_traits<Iter_t>; | |||||
public: | |||||
using iterator_type = Iter_t; | |||||
using iterator_category = typename traits_type::iterator_category; | |||||
using value_type = typename traits_type::value_type; | |||||
using difference_type = typename traits_type::difference_type; | |||||
using reference = typename traits_type::reference; | |||||
using pointer = typename traits_type::pointer; | |||||
//! @} | |||||
//! \name Constructor / Destructor | |||||
//! @{ | |||||
public: | |||||
ring_iterator(const Iter_t base =nullptr) noexcept : | |||||
base_(base), iter_(base) { } | |||||
ring_iterator(const Iter_t base, size_t elem) noexcept : | |||||
base_(base), iter_(base + elem) { } | |||||
ring_iterator(const ring_iterator& it) noexcept : | |||||
base_(it.base_), iter_(it.iter_) { } | |||||
ring_iterator& operator= (const ring_iterator& it) noexcept { | |||||
base_ = it.base_; | |||||
iter_ = it.iter_; | |||||
return *this; | |||||
} | |||||
//! @} | |||||
//! \name Forward iterator requirements | |||||
//! @{ | |||||
public: | |||||
reference operator*() const noexcept { | |||||
return *iter_; | |||||
} | |||||
pointer operator->() const noexcept { | |||||
return iter_; | |||||
} | |||||
ring_iterator& operator++() noexcept { | |||||
if (static_cast<size_t>(++iter_ - base_) >= N) | |||||
iter_ = base_; | |||||
return *this; | |||||
} | |||||
ring_iterator operator++(int) noexcept { | |||||
ring_iterator it = *this; | |||||
if (static_cast<size_t>(++iter_ - base_) >= N) | |||||
iter_ = base_; | |||||
return it; | |||||
} | |||||
//! @} | |||||
//! \name Bidirectional iterator requirements | |||||
//! @{ | |||||
public: | |||||
ring_iterator& operator--() noexcept { | |||||
if (--iter_ < base_) | |||||
iter_ = base_ + N -1; | |||||
return *this; | |||||
} | |||||
ring_iterator operator--(int) noexcept { | |||||
ring_iterator it = *this; | |||||
if (--iter_ < base_) | |||||
iter_ = base_ + N -1; | |||||
return it; | |||||
} | |||||
//! @} | |||||
//! \name Random access iterator requirements | |||||
//! @{ | |||||
reference operator[](difference_type n) const noexcept { | |||||
difference_type k = iter_ - base_; // ptrdiff from base_ | |||||
return (static_cast<size_t>(k + n) < N) ? | |||||
base_[k + n] : // on range | |||||
base_[k + n - N]; // out of range, loop | |||||
} | |||||
ring_iterator& operator+=(difference_type n) noexcept { | |||||
difference_type k = iter_ - base_; // ptrdiff from base_ | |||||
iter_ += (static_cast<size_t>(k + n) < N) ? | |||||
n : // on range | |||||
n - N; // out of range, loop | |||||
return *this; | |||||
} | |||||
ring_iterator operator+(difference_type n) const noexcept { | |||||
difference_type k = iter_ - base_; // ptrdiff from base_ | |||||
return (static_cast<size_t>(k + n) < N) ? | |||||
ring_iterator(base_, k + n) : // on range | |||||
ring_iterator(base_, k + n - N); // out of range, loop | |||||
} | |||||
ring_iterator& operator-=(difference_type n) noexcept { | |||||
difference_type k = iter_ - base_; // ptrdiff from base_ | |||||
iter_ -= ((k - n) < 0)? | |||||
n - N: // out of range, loop | |||||
n; // on range | |||||
return *this; | |||||
} | |||||
ring_iterator operator-(difference_type n) const noexcept { | |||||
difference_type k = iter_ - base_; // ptrdiff from base_ | |||||
return ((k - n) < 0) ? | |||||
ring_iterator(base_, k - n + N) : // out of range, loop | |||||
ring_iterator(base_, k - n); // on range | |||||
} | |||||
//! @} | |||||
//! \name Data members and access | |||||
//! @{ | |||||
const Iter_t& base() const noexcept { | |||||
return base_; | |||||
} | |||||
const Iter_t& iter() const noexcept { | |||||
return iter_; | |||||
} | |||||
size_t size() noexcept { | |||||
return N; | |||||
} | |||||
protected: | |||||
Iter_t base_; | |||||
Iter_t iter_; | |||||
//! @} | |||||
}; | |||||
// Forward iterator requirements | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator==(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() == rhs.iter(); | |||||
} | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator!=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() != rhs.iter(); | |||||
} | |||||
// Random access iterator requirements | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator<(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() < rhs.iter(); | |||||
} | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator<=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() <= rhs.iter(); | |||||
} | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator>(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() > rhs.iter(); | |||||
} | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline bool operator>=(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept { | |||||
return lhs.iter() >= rhs.iter(); | |||||
} | |||||
template<typename Iter_L, typename Iter_R, size_t N> | |||||
inline auto operator-(const ring_iterator<Iter_L, N>& lhs, const ring_iterator<Iter_R, N>& rhs) | |||||
noexcept | |||||
-> decltype(lhs.iter() - rhs.iter()) { | |||||
auto diff = lhs.iter() - rhs.iter(); | |||||
return diff < 0 ? | |||||
diff + N : // loop | |||||
diff; // no loop | |||||
} | |||||
template<typename Iter, size_t N> | |||||
inline ring_iterator<Iter, N> operator+(std::ptrdiff_t lhs, const ring_iterator<Iter, N>& rhs) | |||||
noexcept { | |||||
ring_iterator<Iter, N> it(rhs.iter()); | |||||
return it += lhs; | |||||
} | |||||
} //namespace tbx; | |||||
#endif /* TBX_CORE_RING_ITERATOR_H_ */ |
@@ -0,0 +1,243 @@ | |||||
# | |||||
# Makefile for tbx unit testing | |||||
# | |||||
# Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net> | |||||
# | |||||
# The MIT License (MIT) | |||||
# | |||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
# of this software and associated documentation files (the "Software"), to deal | |||||
# in the Software without restriction, including without limitation the rights | |||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
# copies of the Software, and to permit persons to whom the Software is | |||||
# furnished to do so, subject to the following conditions: | |||||
# | |||||
# The above copyright notice and this permission notice shall be included in all | |||||
# copies or substantial portions of the Software. | |||||
# | |||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
# SOFTWARE. | |||||
# | |||||
# notes: | |||||
# ============== | |||||
# This makefile provides support for unix-like local builds and | |||||
# docker based builds for gcc and clang. | |||||
# ** msvc is not currently supported. | |||||
# | |||||
# Use cases: | |||||
# 1) build localy using **local rules** in terminal. | |||||
# example: | |||||
# make -j4 MK_ARG="-std=c++14 -fconcepts" build-gcc | |||||
# | |||||
# 2) build localy using **docker based rules** via terminal or script | |||||
# in order to compile for all compilers/versions/dialects. | |||||
# example in bash: | |||||
# #!/bin/bash | |||||
# for im in gcc:8 gcc:9 gcc:10; do | |||||
# for dial in -std=c++14 -std=c++17; do | |||||
# make IMAGE="$im" MK_ARG="$dial" dock-gcc | |||||
# done | |||||
# done | |||||
# | |||||
# 3) build inside a docker instance using **local rules** in order to | |||||
# build and test using a CD/CI system. | |||||
# example in a yml file: | |||||
# image: gcc:8 | |||||
# build: | |||||
# stage: build | |||||
# - make MK_ARG="-std=c++14" build-gcc | |||||
# - make MK_ARG="-std=c++14 -fconcepts" build-gcc | |||||
# - make MK_ARG="-std=c++17" build-gcc | |||||
# - make MK_ARG="-std=c++17 -fconcepts" build-gcc | |||||
# - make MK_ARG="-std=c++2a" build-gcc | |||||
# ... etc | |||||
# test: | |||||
# stage: test | |||||
# - bin/utlTest | |||||
# ... etc | |||||
# | |||||
# | |||||
# ============== Project settings ============== | |||||
# | |||||
# note: STM32f101RC/D/E device configuration on SMT32CubeF1 library requires: | |||||
# 1) STM2F101xE pre-define | |||||
# 2) startup_stm32f101xe.s startup file | |||||
# | |||||
# Project's name | |||||
PROJECT := tbx | |||||
# Excecutable's name | |||||
TARGET := tbxTest | |||||
# Source directories list(space seperated). Relative path, under current directory only | |||||
SRC_DIR_LIST := tests gtest | |||||
# Source files list(space seperated). | |||||
SRC_FILES_LIST := | |||||
# Include directories list(space seperated). Relative path | |||||
INC_DIR_LIST := ../include gtest | |||||
# Exclude files list(space seperated). Filenames only. | |||||
# EXC_FILE_LIST := bad.cpp old.cpp | |||||
# Build directories | |||||
BUILD_DIR := bin | |||||
OBJ_DIR := $(BUILD_DIR)/obj | |||||
DEP_DIR := $(BUILD_DIR)/.dep | |||||
# ============== Compiler settings ============== | |||||
CLANGXX := clang++ | |||||
GCCXX := g++ | |||||
CSIZE := size | |||||
ODUMP := objdump | |||||
OCOPY := objcopy | |||||
# Compiler flags for debug and release | |||||
DEB_CFLAGS := -std=c++17 -DDEBUG -g3 -Wall -Wextra | |||||
REL_CFLAGS := -std=c++17 -Wall -Wextra -O2 | |||||
# Pre-defines | |||||
# PRE_DEFS := MYCAB=1729 SUPER_MODE | |||||
# ============== Linker settings ============== | |||||
# Linker flags | |||||
LDFLAGS := -pthread | |||||
# Map output file | |||||
MAP_FILE := output.map | |||||
MAP_FLAG := -Xlinker -Map=$(BUILD_DIR)/$(MAP_FILE) | |||||
# ============== Docker settings ============== | |||||
# We need: | |||||
# 1) Bind the entire project directory(the dir that icludes all the code) as volume. | |||||
# 2) In docker instance change to working directory(where the makefile is). | |||||
# For utl we use the directories `${PWD%/*}` and `test`. | |||||
# We double-$$ for double evaluating. | |||||
DOCKER_VOL_DIR := "$${PWD%/*}" | |||||
DOCKER_WRK_DIR := test | |||||
DOCKER_RUN := docker run --rm -v $(DOCKER_VOL_DIR):/usr/src/$(PROJECT) -w /usr/src/$(PROJECT)/$(DOCKER_WRK_DIR) | |||||
# ============== Default settings ============== | |||||
# compiler and compiler flags. By default docker is not used. | |||||
CFLAGS := $(DEB_CFLAGS) | |||||
CXX := $(GCCXX) | |||||
DOCKER := | |||||
# | |||||
# =========== Main body and Patterns =========== | |||||
# | |||||
ifeq ($(OS), Windows_NT) | |||||
TARGET := $(TARGET).exe | |||||
endif | |||||
INC := $(foreach dir,$(INC_DIR_LIST),-I$(dir)) | |||||
DEF := $(foreach def,$(PRE_DEFS),-D$(def)) | |||||
EXC := $(foreach fil,$(EXC_FILE_LIST), \ | |||||
$(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/$(fil))) \ | |||||
) | |||||
# source files, object and dependencies list | |||||
# recursive search into current and source directories | |||||
SRC := $(wildcard *.cpp) | |||||
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/*.cpp)) | |||||
SRC += $(foreach dir,$(SRC_DIR_LIST),$(wildcard $(dir)/**/*.cpp)) | |||||
#SRC := $(abspath $(filter-out $(EXC),$(SRC))) | |||||
SRC := $(filter-out $(EXC),$(SRC)) | |||||
OBJ := $(foreach file,$(SRC:%.cpp=%.o),$(OBJ_DIR)/$(file)) | |||||
DEP := $(foreach file,$(SRC:%.cpp=%.d),$(DEP_DIR)/$(file)) | |||||
# Make Dependencies pattern. | |||||
# This little trick enables recompilation only when dependencies change | |||||
# and it does so for changes both in source AND header files ;) | |||||
# | |||||
# It is based on Tom Tromey's method. | |||||
# | |||||
# Invoke cpp to create makefile rules with dependencies for each source file | |||||
$(DEP_DIR)/%.d: %.cpp | |||||
@mkdir -p $(@D) | |||||
@$(DOCKER) $(CXX) -E $(CFLAGS) $(INC) $(DEF) -MM -MT $(OBJ_DIR)/$(<:.cpp=.o) -MF $@ $< | |||||
# objects depent on .cpp AND dependency files, which have an empty recipe | |||||
$(OBJ_DIR)/%.o: %.cpp $(DEP_DIR)/%.d | |||||
@mkdir -p $(@D) | |||||
$(DOCKER) $(CXX) -c $(CFLAGS) $(INC) $(DEF) -o $@ $< | |||||
# empty recipe for dependency files. This prevents make errors | |||||
$(DEP): | |||||
# now include all dependencies | |||||
# After all they are makefile dependency rules ;) | |||||
include $(wildcard $(DEP)) | |||||
# main target rule | |||||
$(BUILD_DIR)/$(TARGET): $(OBJ) | |||||
@mkdir -p $(@D) | |||||
@echo Linking to target: $(TARGET) | |||||
$(DOCKER) $(CXX) $(LDFLAGS) $(MAP_FLAG) -o $(@D)/$(TARGET) $(OBJ) | |||||
$(DOCKER) $(ODUMP) -h -S $(BUILD_DIR)/$(TARGET) > $(BUILD_DIR)/$(basename $(TARGET)).list | |||||
$(DOCKER) $(OCOPY) -O ihex $(BUILD_DIR)/$(TARGET) $(BUILD_DIR)/$(basename $(TARGET)).hex | |||||
@echo | |||||
@echo Print size information | |||||
@$(CSIZE) $(@D)/$(TARGET) | |||||
@echo Done | |||||
.PHONY: clean | |||||
clean: | |||||
@echo Cleaning build directories | |||||
@rm -rf $(OBJ_DIR) | |||||
@rm -rf $(DEP_DIR) | |||||
@rm -rf $(BUILD_DIR) | |||||
# | |||||
# ================ Local build rules ================= | |||||
# examples: | |||||
# make MK_ARG="-std=c++14 -fconcepts" build-gcc | |||||
# make MK_ARG="-std=c++17" build-clang | |||||
# | |||||
.PHONY: build-gcc | |||||
build-gcc: CFLAGS += $(MK_ARG) | |||||
build-gcc: $(BUILD_DIR)/$(TARGET) | |||||
.PHONY: build-clang | |||||
build-clang: CXX := $(CLANGXX) | |||||
build-clang: CFLAGS += $(MK_ARG) | |||||
build-clang: $(BUILD_DIR)/$(TARGET) | |||||
.PHONY: debug | |||||
debug: $(BUILD_DIR)/$(TARGET) | |||||
.PHONY: release | |||||
release: CFLAGS := $(REL_FLAGS) | |||||
release: clean $(BUILD_DIR)/$(TARGET) | |||||
.PHONY: all | |||||
all: clean release | |||||
# | |||||
# ================ Docker based rules ================ | |||||
# examples: | |||||
# make IMAGE="gcc:8.3" MK_ARG="-std=c++14 -fconcepts" dock-gcc | |||||
# make IMAGE="a-clang-image" MK_ARG="-std=c++17" dock-clang | |||||
# | |||||
.PHONY: dock-gcc | |||||
dock-gcc: DOCKER := $(DOCKER_RUN) $(IMAGE) | |||||
dock-gcc: CFLAGS += $(MK_ARG) | |||||
dock-gcc: $(BUILD_DIR)/$(TARGET) | |||||
.PHONY: dock-clang | |||||
dock-clang: CXX := $(CLANGXX) | |||||
dock-clang: DOCKER := $(DOCKER_RUN) $(IMAGE) | |||||
dock-clang: CFLAGS += $(MK_ARG) | |||||
dock-clang: $(BUILD_DIR)/$(TARGET) | |||||
@@ -0,0 +1,34 @@ | |||||
/*! | |||||
* \file main.cpp | |||||
* \brief Test project main file | |||||
* | |||||
* \copyright Copyright (C) 2020-2021 Christos Choutouridis <christos@choutouridis.net> | |||||
* | |||||
* <dl class=\"section copyright\"><dt>License</dt><dd> | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in all | |||||
* copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
* SOFTWARE. | |||||
* </dd></dl> | |||||
* | |||||
*/ | |||||
#include <gtest/gtest.h> | |||||
GTEST_API_ int main(int argc, char **argv) { | |||||
testing::InitGoogleTest(&argc, argv); | |||||
return RUN_ALL_TESTS(); | |||||
} | |||||
@@ -0,0 +1,231 @@ | |||||
/*! | |||||
* \file ring_iterator.cpp | |||||
* \brief | |||||
* Unit tests for ring_iterator | |||||
* | |||||
* \copyright Copyright (C) 2020 Christos Choutouridis <christos@choutouridis.net> | |||||
* | |||||
* <dl class=\"section copyright\"><dt>License</dt><dd> | |||||
* The MIT License (MIT) | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||||
* of this software and associated documentation files (the "Software"), to deal | |||||
* in the Software without restriction, including without limitation the rights | |||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||||
* copies of the Software, and to permit persons to whom the Software is | |||||
* furnished to do so, subject to the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included in all | |||||
* copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |||||
* SOFTWARE. | |||||
* </dd></dl> | |||||
* | |||||
*/ | |||||
#include <core/ring_iterator.h> | |||||
#include <gtest/gtest.h> | |||||
#include <array> | |||||
#include <type_traits> | |||||
namespace Tring_iterator { | |||||
using namespace tbx; | |||||
// Test construction | |||||
TEST(Tring_iterator, construct) { | |||||
int A[10]; | |||||
//default constructor | |||||
ring_iterator<int*, 10> i1; | |||||
EXPECT_EQ(nullptr, i1.base()); | |||||
EXPECT_EQ(nullptr, i1.iter()); | |||||
EXPECT_EQ(10UL, i1.size()); | |||||
// implementation specific (you can remove it freely) | |||||
EXPECT_EQ(2*sizeof(int*), sizeof(i1)); | |||||
// basic | |||||
ring_iterator<int*, 10> i2(A); | |||||
EXPECT_EQ(A, i2.base()); | |||||
EXPECT_EQ(A, i2.iter()); | |||||
EXPECT_EQ(10UL, i2.size()); | |||||
// basic from assignment | |||||
ring_iterator<int*, 10> i3 = A; | |||||
EXPECT_EQ(A, i3.base()); | |||||
EXPECT_EQ(A, i3.iter()); | |||||
EXPECT_EQ(10UL, i3.size()); | |||||
// basic with offset | |||||
ring_iterator<int*, 10> i4(A, 5); | |||||
EXPECT_EQ(A, i4.base()); | |||||
EXPECT_EQ(&A[5], i4.iter()); | |||||
EXPECT_EQ(10UL, i4.size()); | |||||
// copy (Legacy iterator) | |||||
auto i5 = i2; | |||||
EXPECT_EQ(A, i5.base()); | |||||
EXPECT_EQ(A, i5.iter()); | |||||
EXPECT_EQ(10UL, i5.size()); | |||||
// arbitrary type | |||||
struct TT { int a,b,c; }; | |||||
std::array<TT, 10> t; | |||||
ring_iterator<TT*, 10> it(t.data(), 2); | |||||
EXPECT_EQ(t.begin(), it.base()); | |||||
EXPECT_EQ(&t[2], it.iter()); | |||||
EXPECT_EQ(10UL, it.size()); | |||||
} | |||||
// Legacy iterator | |||||
TEST(Tring_iterator, LegacyIterator) { | |||||
EXPECT_EQ(true, (std::is_same<int, typename ring_iterator<int*, 10>::value_type>::value)); | |||||
EXPECT_EQ(true, (std::is_same<std::ptrdiff_t, typename ring_iterator<int*, 10>::difference_type>::value)); | |||||
EXPECT_EQ(true, (std::is_same<int&, typename ring_iterator<int*, 10>::reference>::value)); | |||||
EXPECT_EQ(true, (std::is_same<int*, typename ring_iterator<int*, 10>::pointer>::value)); | |||||
EXPECT_EQ(true, (std::is_same<std::random_access_iterator_tag, typename ring_iterator<int*, 10>::iterator_category>::value)); | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> i1(A); | |||||
// copy constructible/assignable | |||||
auto i2 = i1; | |||||
EXPECT_EQ(A, i2.base()); | |||||
EXPECT_EQ(A, i2.iter()); | |||||
EXPECT_EQ(10UL, i2.size()); | |||||
// dereferenceable - incrementable | |||||
ring_iterator<int*, 10> i3(A); | |||||
EXPECT_EQ(true, (std::is_reference<decltype(*i3)>::value)); | |||||
EXPECT_EQ(true, (std::is_same<ring_iterator<int*, 10>&, decltype(++i3)>::value)); | |||||
EXPECT_EQ(true, (std::is_reference<decltype((*i3++))>::value)); | |||||
// more practical | |||||
ring_iterator<int*, 10> i4(A); | |||||
ring_iterator<int*, 10> i5(A, 9); | |||||
EXPECT_EQ(A[0], *i4); | |||||
EXPECT_EQ(&A[1], (++i4).iter()); | |||||
// check loop | |||||
EXPECT_EQ(A[9], *i5); | |||||
EXPECT_EQ(&A[0], (++i5).iter()); | |||||
} | |||||
// Legacy input iterator | |||||
TEST(Tring_iterator, LegacyInputIterator) { | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> i1(A), i2(A), i3(A, 1); | |||||
struct T { int m; }; | |||||
T B[5] { {0}, {1}, {2}, {3}, {4}}; | |||||
ring_iterator<T*, 5> it(B); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(i1 == i2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(i1 != i2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<int&, decltype(*i1)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<int, decltype(it->m)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>&, decltype(++i1)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<int&, decltype(*i1++)>::value)); | |||||
// more practical | |||||
EXPECT_EQ (true, i1 == i2); | |||||
EXPECT_EQ (true, i1 != i3); | |||||
EXPECT_EQ (0, *i1); | |||||
EXPECT_EQ (0, it->m); | |||||
EXPECT_EQ (true, (++i1 == i3)); | |||||
EXPECT_EQ (1, *i1++); | |||||
EXPECT_EQ (2, *i1); | |||||
} | |||||
// Legacy input iterator | |||||
TEST(Tring_iterator, LegacyOutputIterator) { | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> it(A); | |||||
EXPECT_EQ (true, (std::is_assignable<decltype(*it), int>::value)); | |||||
EXPECT_EQ (true, (std::is_assignable<decltype(*it++), int>::value)); | |||||
// more practical | |||||
*it = 42; | |||||
EXPECT_EQ (42, A[0]); | |||||
*it++ = 7; | |||||
EXPECT_EQ (7, A[0]); | |||||
EXPECT_EQ (&A[1], it.iter()); | |||||
} | |||||
// Legacy forward iterator | |||||
TEST(Tring_iterator, LegacyForwardIterator) | |||||
{ | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> it(A); | |||||
EXPECT_EQ (0, *it++); | |||||
EXPECT_EQ (1, *it); | |||||
} | |||||
// Legacy bidirectional iterator | |||||
TEST(Tring_iterator, LegacyBidirectionalIterator) { | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> it(A); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>&, decltype(--it)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>, decltype(it--)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<int&, decltype(*it--)>::value)); | |||||
// more practical | |||||
ring_iterator<int*, 10> i1(A), i2(A, 9); | |||||
EXPECT_EQ (9, *i2--); // check loop also | |||||
EXPECT_EQ (8, *i2); | |||||
EXPECT_EQ (0, *i1--); // check loop also | |||||
EXPECT_EQ (9, *i1); | |||||
} | |||||
// Legacy random access iterator | |||||
TEST(Tring_iterator, LegacyRandomAccessIterator) { | |||||
int A[10] {0, 1, 2, 3, 4, 5, 6, 7, 8 , 9}; | |||||
ring_iterator<int*, 10> it1(A), it2(A, 7); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>&, decltype(it1 += 7)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>, decltype(it1 + 7)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>, decltype(7 + it1)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>&, decltype(it1 -= 7)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<ring_iterator<int*, 10>, decltype(it1 - 7)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<std::ptrdiff_t, decltype(it1 - it2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<int&, decltype(it1[7])>::value)); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(it1 < it2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(it1 > it2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(it1 <= it2)>::value)); | |||||
EXPECT_EQ (true, (std::is_same<bool, decltype(it1 >= it2)>::value)); | |||||
// more practical | |||||
ring_iterator<int*, 10> i1(A), i2(A); | |||||
i1 += 7; | |||||
EXPECT_EQ (7, *i1); | |||||
i1 -= 7; | |||||
EXPECT_EQ (0, *i1); | |||||
i1 += 11; | |||||
EXPECT_EQ (1, *i1); | |||||
i1 -= 2; | |||||
EXPECT_EQ (9, *i1); | |||||
EXPECT_EQ (7, *(i2+7)); | |||||
EXPECT_EQ (7, *(7+i2)); | |||||
EXPECT_EQ (1, *(i2+11)); | |||||
EXPECT_EQ (1, *(11+i2)); | |||||
EXPECT_EQ (7, *(i1-2)); | |||||
EXPECT_EQ (8, *(i2-2)); | |||||
EXPECT_EQ (9, (i1 - i2)); | |||||
EXPECT_EQ (1, (i2 - i1)); // loop | |||||
} | |||||
} |