@@ -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 | |||
} | |||
} |