enum EComparisonType {
EQ,
NOT_EQ,
LESS,
GREATER,
LESS_OR_EQ,
GREATER_OR_EQ
};
template <const EComparisonType>
// Functor
struct Compare {};
template<>
struct Compare<EComparisonType::EQ> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first == second;
}
};
template<>
struct Compare<EComparisonType::NOT_EQ> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first != second;
}
};
template<>
struct Compare<EComparisonType::LESS> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first < second;
}
};
template<>
struct Compare<EComparisonType::LESS_OR_EQ> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first <= second;
}
};
template<>
struct Compare<EComparisonType::GREATER> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first > second;
}
};
template<>
struct Compare<EComparisonType::GREATER_OR_EQ> {
template <typename T, class U>
bool operator()(const T& first, const U& second) throw() {
return first >= second;
}
};
#include <cstddef>
#include <cstdint>
#include <type_traits>
// bool val. to bool type
template <const bool Bool>
struct BoolType {};
template<>
struct BoolType<true> {
typedef std::true_type Type;
};
template<>
struct BoolType<false> {
typedef std::false_type Type;
};
#define BOOL_TYPE(BoolVal) BoolType<BoolVal>::Type
// HINT: std::add_const / std::remove_const also can be used
template <typename T, const bool Constant>
struct AddRemoveConst {};
template <typename T>
struct AddRemoveConst<T, true> {
typedef const T Type;
};
template <typename T>
struct AddRemoveConst<T, false> {
typedef T Type;
};
#define ADD_REMOVE_CONST(Type, StaticPredicate) AddRemoveConst<Type, StaticPredicate>::Type
// std::is_fundamental [http://w...content-available-to-author-only...s.com/reference/type_traits/is_fundamental/]
enum class ECFundamentalTypeTags {
UNIDENTIFIED,
BOOL,
SIGNED_CHAR,
UNSIGNED_CHAR,
// Signedness of wchar_t is unspecified
// [http://stackoverflow.com/questions/11953363/wchar-t-is-unsigned-or-signed]
WCHAR,
//// 'char16_t' AND 'char32_t' SHOULD be a keywords since the C++11,
//// BUT MS VS Community 2013 Upd 5 does NOT supports that
//// AND specifys 'char16_t' AND 'char32_t' as a typdef aliases instead
//// (so they are NOT presented here)
SIGNED_SHORT_INT,
UNSIGNED_SHORT_INT,
SIGNED_INT,
UNSIGNED_INT,
SIGNED_LONG_INT,
UNSIGNED_LONG_INT,
SIGNED_LONG_LONG_INT, // C++11
UNSIGNED_LONG_LONG_INT, // C++11
FLOAT,
DOUBLE,
LONG_DOUBLE,
VOID_,
NULLPTR // C++11 std::nullptr_t
};
template <typename T, class TypeTags = ECFundamentalTypeTags>
struct TypeTag {
static const auto TAG = TypeTags::UNIDENTIFIED;
};
template <class TypeTags>
struct TypeTag<bool, TypeTags> {
static const auto TAG = TypeTags::BOOL;
};
template <class TypeTags>
struct TypeTag<signed char, TypeTags> {
static const auto TAG = TypeTags::SIGNED_CHAR;
};
template <class TypeTags>
struct TypeTag<unsigned char, TypeTags> {
static const auto TAG = TypeTags::UNSIGNED_CHAR;
};
template <class TypeTags>
struct TypeTag<wchar_t, TypeTags> {
static const auto TAG = TypeTags::WCHAR;
};
template <class TypeTags>
struct TypeTag<signed short int, TypeTags> {
static const auto TAG = TypeTags::SIGNED_SHORT_INT;
};
template <class TypeTags>
struct TypeTag<unsigned short int, TypeTags> {
static const auto TAG = TypeTags::UNSIGNED_SHORT_INT;
};
template <class TypeTags>
struct TypeTag<signed int, TypeTags> {
static const auto TAG = TypeTags::SIGNED_INT;
};
template <class TypeTags>
struct TypeTag<unsigned int, TypeTags> {
static const auto TAG = TypeTags::UNSIGNED_INT;
};
template <class TypeTags>
struct TypeTag<signed long int, TypeTags> {
static const auto TAG = TypeTags::SIGNED_LONG_INT;
};
template <class TypeTags>
struct TypeTag<unsigned long int, TypeTags> {
static const auto TAG = TypeTags::UNSIGNED_LONG_INT;
};
template <class TypeTags>
struct TypeTag<signed long long int, TypeTags> {
static const auto TAG = TypeTags::SIGNED_LONG_LONG_INT;
};
template <class TypeTags>
struct TypeTag<unsigned long long int, TypeTags> {
static const auto TAG = TypeTags::UNSIGNED_LONG_LONG_INT;
};
template <class TypeTags>
struct TypeTag<float, TypeTags> {
static const auto TAG = TypeTags::FLOAT;
};
template <class TypeTags>
struct TypeTag<double, TypeTags> {
static const auto TAG = TypeTags::DOUBLE;
};
template <class TypeTags>
struct TypeTag<long double, TypeTags> {
static const auto TAG = TypeTags::LONG_DOUBLE;
};
template <class TypeTags>
struct TypeTag<void, TypeTags> {
static const auto TAG = TypeTags::VOID_;
};
template <class TypeTags>
struct TypeTag<std::nullptr_t, TypeTags> {
static const auto TAG = TypeTags::NULLPTR;
};
#define TYPE_TAG(Object) TypeTag<std::decay<decltype(Object)>::type>::TAG
// Size is in bytes
// Fixed width integer types (since C++11): http://e...content-available-to-author-only...e.com/w/cpp/types/integer
// See also: http://w...content-available-to-author-only...4.com/en/t/0012/
template <const size_t Size, const bool Signed>
struct IntegralTypeBySize {
static const auto TAG = ECFundamentalTypeTags::UNIDENTIFIED;
};
template<>
struct IntegralTypeBySize<1U, true> {
typedef int8_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<2U, true> {
typedef int16_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<4U, true> {
typedef int32_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<8U, true> {
typedef int64_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<1U, false> {
typedef uint8_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<2U, false> {
typedef uint16_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<4U, false> {
typedef uint32_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
template<>
struct IntegralTypeBySize<8U, false> {
typedef uint64_t Type;
static const auto TAG = TypeTag<Type, ECFundamentalTypeTags>::TAG;
};
//// Random Access Iterator [http://e...content-available-to-author-only...e.com/w/cpp/concept/RandomAccessIterator]
#include <limits>
#include <iterator>
// [!] Do NOT change an order of the elements NOR alter the sequence
// coze it may break an internal comparison logic [!]
enum EIterPosType {
IPT_BEFORE_BEGIN,
IPT_BEFORE_REVERSED_BEGIN,
IPT_NORMAL,
IPT_PAST_THE_END,
IPT_PAST_THE_REVERSED_END
};
//// Key features:
//// 1) functionality (bidirectional + random access)
//// 2) safety (the ONLY way to invalidate an iterator is to destroy the related container object)
//// 3) versatility (CAN provide mutable/read-only access AND switch direction/container at the real time)
//// 4) commonality (CAN be used with the multiple container types which satisfies the requirements)
//// [!] PERFORMANCE WARNING: for efficient use,
//// related container SHOULD provide fast access to the ANY item by its idx. [!]
//// Traits:
//// 1) dereferenceable
//// (even in 'past-the-end', 'before-begin' OR singular/invalidated state,
//// returning ref. to the mock obj. in those cases)
//// 2) incrementable
//// 3) swappable: meet the requirements of 'MoveAssignable' and 'MoveConstructible'
//// (http://e...content-available-to-author-only...e.com/w/cpp/concept/Swappable,
//// http://e...content-available-to-author-only...e.com/w/cpp/algorithm/swap)
// 'TContainerType' should support the following properties, fileds AND methods:
// 'value_type', 'operator[]()', 'size()', 'empty()'
template <typename TContainerType, class TContainerElemType,
const bool Reversed = false, const bool Constant = true>
// C++ iterator concept: http://e...content-available-to-author-only...e.com/w/cpp/concept/Iterator
// Random-access iterators are iterators that can be used to access (AND modify if 'Constant' is false)
// elements at an arbitrary offset position relative to the element they point to,
// offering the same functionality as pointers (to constants if 'Constant' is true)
// [!] Does NOT thread safe (BUT satisfy BASIC STL thread safety guarantee:
// http://e...content-available-to-author-only...e.com/w/cpp/container#Iterator_invalidation) [!]
class GenericRAIterator : public std::iterator<std::random_access_iterator_tag, TContainerElemType> {
public:
//// From the base class
typedef typename std::iterator<std::random_access_iterator_tag, TContainerElemType>::value_type value_type;
typedef typename std::iterator<std::random_access_iterator_tag, TContainerElemType>::difference_type difference_type;
typedef typename BOOL_TYPE(Constant) TConstantnessType;
static const auto CONSTANT = Constant;
static const size_t MAX_HANDLED_ELEMS;
//// Use 'Constant' to make iterator type mutable (switch work mode from input to input-output)
typedef typename AddRemoveConst<TContainerType, Constant>::Type TMutableContainerType;
typedef typename AddRemoveConst<value_type, Constant>::Type TMutableValueType;
typedef typename std::iterator<std::random_access_iterator_tag, value_type> TBaseIterType;
// Creates a 'begin' OR 'rbegin' (see here: http://e...content-available-to-author-only...e.com/w/cpp/container/vector/rbegin)
// linked OR unliked iterator
GenericRAIterator(TMutableContainerType* const container = nullptr,
const bool reversed = Reversed) throw()
: reversed_(reversed)
{
linkToTheContainer(container); // alseo sets pos.
}
//// [!] Move constructor AND move operator will be ALSO auto. generated by the compiler
//// AND will behaves like it's 'copy' equivalents [!]
//// TO DO: allow to construct (AND assign) constant iter. from the NONE constant one
GenericRAIterator(const GenericRAIterator&) = default;
GenericRAIterator& operator=(const GenericRAIterator&) = default;
~GenericRAIterator() throw() {
linkToTheContainer(); // unlink
}
//// 'at', 'operator*', 'operator->' AND 'operator[]'
//// returns ref. (ptr) to the mock element in case of ERROR
TMutableValueType& operator*() const throw() {
return at(pos()); // curr. pos
}
TMutableValueType* operator->() const throw() {
return std::addressof(operator*());
}
TMutableValueType& operator[](const difference_type idx) const throw() {
return at(getShiftedPos(idx)); // shift to the curr. pos
}
GenericRAIterator& operator++() throw() {
return (*this += 1); // invoke operator+=''
}
GenericRAIterator operator++(const int) throw() {
GenericRAIterator copy(*this);
operator++();
return std::move(copy);
}
GenericRAIterator& operator--() throw() {
return (*this -= 1); // 'invoke operator-='
}
GenericRAIterator operator--(const int) throw() {
GenericRAIterator copy(*this);
operator--();
return std::move(copy);
}
//// 'shift' can be both positive or negative; the complexity SHOULD be constant
GenericRAIterator& operator+=(const difference_type shift) throw() {
setPos(getShiftedPos(shift)); // updated pos.
return *this;
}
GenericRAIterator& operator-=(const difference_type shift) throw() {
return (*this += -shift); // exec. 'operator+=()'
}
EIterPosType posType() const throw() {
static_assert(EIterPosType::IPT_BEFORE_BEGIN < EIterPosType::IPT_NORMAL &&
EIterPosType::IPT_NORMAL < EIterPosType::IPT_PAST_THE_END,
"Incorrect 'EIterPosType' values order");
if (pos() < 0) return reversed() ? EIterPosType::IPT_PAST_THE_REVERSED_END
: EIterPosType::IPT_BEFORE_BEGIN;
#pragma warning(disable: 4018) // signed/unsigned mismatch: 'pos() >= container()->size()'
if (pos() >= container()->size()) return reversed() ? EIterPosType::IPT_BEFORE_REVERSED_BEGIN
: EIterPosType::IPT_PAST_THE_END;
#pragma warning(default: 4018)
return EIterPosType::IPT_NORMAL;
}
//// Note that for the types that are both 'EqualityComparable' AND 'LessThanComparable',
//// the C++ standard library makes a distinction between
//// 'equality', which is the value of the expression 'a == b' AND
//// 'equivalence', which is the value of the expression '!(a < b) && !(b < a)'
template <const bool OtherReversed, const bool OtherConstant, const EComparisonType ComparisonType>
bool compare(const GenericRAIterator<TContainerType, value_type, OtherReversed, OtherConstant>& iter,
const bool checkType = false) const throw()
{
// constexpr ('returnValBasedOnEq' AND 'isEq')??
auto returnValBasedOnEq = [&](const bool isEq) throw() { // ONLY if SHOULD NOT do actual compare
switch (ComparisonType) {
case EComparisonType::EQ:
case EComparisonType::LESS_OR_EQ:
case EComparisonType::GREATER_OR_EQ:
return isEq;
case EComparisonType::LESS:
case EComparisonType::GREATER:
return false;
}
return !isEq; // '!='
};
if (this == &iter) return returnValBasedOnEq(true); // same instance
// Diff. type iters are diff. even if they linked to the same sequence [CAN NOT be comparable]
if (checkType && reversed() != iter.reversed()) return returnValBasedOnEq(false);
if (container() != iter.container())
return returnValBasedOnEq(false); // diff. containers (diff. domains)
if (!container()) return returnValBasedOnEq(true); // both a NONE-iterators (unlinked)
// 'std::vector::end' - if the container is empty, this function returns the same as vector::begin
// For an empty container 'begin' == 'end' AND so let the 'rbegin' == 'rend'
// AND ALL other iters are the same
if (container()->empty()) return returnValBasedOnEq(true);
const auto thisPosType = posType();
if (EIterPosType::IPT_NORMAL == thisPosType) {
auto thisPos = pos(), otherPos = iter.pos();
if (reversed()) std::swap(thisPos, otherPos);
return Compare<ComparisonType>()(thisPos, otherPos); // comparing absolute pos.
}
// Past-the-end OR before-begin: comparing relative pos.
return Compare<ComparisonType>()(thisPosType, iter.posType());
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator==(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return compare<OtherReversed, OtherConstant, EComparisonType::EQ>(iter);
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator!=(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return !(*this == iter); // invoke 'operator==(const GenericRAIterator&)'
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator<(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return compare<OtherReversed, OtherConstant, EComparisonType::LESS>(iter);
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator>(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return compare<OtherReversed, OtherConstant, EComparisonType::GREATER>(iter);
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator<=(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return compare<OtherReversed, OtherConstant, EComparisonType::LESS_OR_EQ>(iter);
}
template <const bool OtherReversed, const bool OtherConstant>
bool operator>=(const GenericRAIterator<TContainerType, value_type,
OtherReversed, OtherConstant>& iter) const throw() {
return compare<OtherReversed, OtherConstant, EComparisonType::GREATER_OR_EQ>(iter);
}
// Resets pos.: moves pos. to the 'begin' OR 'rbegin'
// (OR 'past-the-end' - if empty) based on the iter. type
void reset() throw() {
if (container()) { // if linked
if (reversed()) { // end -> begin
const auto size = container()->size();
// 'rbegin' OR past-the-end (if empty) [http://w...content-available-to-author-only...s.com/reference/vector/vector/rbegin/]
setPos(size ? size - 1 : 0);
} else {
// 'begin' OR past-the-end (if empty) [http://w...content-available-to-author-only...s.com/reference/vector/vector/begin/]
setPos();
}
} else setPos(); // unlinked
}
// Resets iter. AND removes the reversion (if reversed)
void clear() throw() {
reset();
if (reversed()) reverse(); // make unreversed
}
// Called with NO data provided will partially invalidate the iterator -
// partially invalid iterator will be left in the valid, BUT unlinked state
// Also resets pos.
void linkToTheContainer(TMutableContainerType* const container = nullptr) throw() {
setContainer(container);
reset();
}
// Returns false if unlinked
// Despite it's name, the func. can NOT 100% gurantee the instance is surely valid
// (the linked container CAN be already destroyed)
bool valid() const throw() {
return (nullptr != container()); // false if unlinked
}
bool dereferencable() const throw() {
if (!valid()) return false; // invalid
#pragma warning(disable: 4018) // signed/unsigned mismatch: 'pos() < container()->size()'
// Valid pos. (NOT 'past-the-end' NOR 'before-begin')
return ((pos() > -1) && (pos() < container()->size()));
#pragma warning(default: 4018)
}
private:
//// 'ErrMsg' mutable member was removed in order to satisfy STL thread safety standart,
//// which says that 'all const member functions can be called concurrently by different
//// threads on the same object, more generally, the C++ standard library functions
//// do not modify objects unless those objects are accessible, directly or indirectly'
bool reversed_ = Reversed;
difference_type pos__ = difference_type(); // absolute pos. [-1, container_->size()]
TMutableContainerType* container_ = nullptr;
public:
TMutableValueType& at(const decltype(pos__) pos) const throw() {
static TMutableValueType DUMMY = TMutableValueType(); // will be zeroised (default created) as a static
if (container()) {
#pragma warning(disable: 4018) // signed/unsigned mismatch: 'pos > containerPtr->size()'
if (pos < 0 || pos > container()->size()) {
return DUMMY; // attempt to dereference a before-begin OR past-the-end iterato
}
#pragma warning(default: 4018)
return (*container())[pos];
}
return DUMMY; // attempt to dereference an unlinked (singular) iterator
}
void reverse() throw() {
reversed_ = !reversed_;
}
auto reversed() const throw() -> decltype(reversed_) {
return reversed_;
}
// If pos. after the last elem.: 'past-the-end'; if before first: 'before-begin'
// If the related container is empty -
// ALL 'past-the-end' AND 'before-begin' iterators are considered equal
// (pointing to the no-element)
// Given some none-empty container with last elem idx. is '2' (for example),
// ANY 'past-the-end' iterators linked to this conainer
// are considered equal, regardless of their actual pos. - 3, 5 OR 1000 etc.
// (same logic for the 'before-begin' iterators: -1, -7, -300 iterators are considered equal)
auto pos() const throw() -> decltype(pos__) {
return pos__;
}
auto container() const throw() -> decltype(container_) {
return container_;
}
private:
void setPos(const decltype(pos__) pos = 0) throw() {
pos__ = pos;
}
void setContainer(decltype(container_) const container = nullptr) throw() {
container_ = container;
}
auto getShiftedPos(const difference_type shift = 0U) const throw() -> decltype(pos__) {
return pos__ + (reversed_ ? -shift : shift);
}
};
template <typename TContainerType, class TContainerElemType,
const bool Reversed, const bool Constant>
const size_t
GenericRAIterator<TContainerType, TContainerElemType, Reversed, Constant>::MAX_HANDLED_ELEMS
= std::numeric_limits<decltype(pos__)>::max() + 1U;
template <typename TContainerType, class TContainerElemType,
const bool Reversed, const bool Constant>
GenericRAIterator<TContainerType, TContainerElemType, Reversed, Constant>
operator+(const GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>& iter,
typename GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>::difference_type const shift) throw()
{
auto copy(iter);
copy += shift;
return std::move(copy);
}
template <typename TContainerType, class TContainerElemType,
const bool Reversed, const bool Constant>
GenericRAIterator<TContainerType, TContainerElemType, Reversed, Constant>
operator+(typename GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>::difference_type const shift,
const GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>& iter) throw()
{
return std::move(iter + shift); // exec. 'operator+(iter_type, diff_type)'
}
template <typename TContainerType, class TContainerElemType,
const bool Reversed, const bool Constant>
GenericRAIterator<TContainerType, TContainerElemType, Reversed, Constant>
operator-(const GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>& iter,
typename GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant>::difference_type const shift) throw()
{
return std::move(iter + (-shift)); // exec. 'operator+(iter_type, diff_type)'
}
// Retruns max. value if diff. domain
// Precondition: a + n == b; Postcondition: b == a + (b - a)
template <typename TContainerType, class TContainerElemType,
const bool Reversed, const bool Constant1, const bool Constant2>
auto operator-(const GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant1>& iter1,
const GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant2>& iter2) throw()
-> typename GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant1>::difference_type
{
typedef typename GenericRAIterator<TContainerType, TContainerElemType,
Reversed, Constant1>::difference_type difference_type;
// If diff. domain
if (iter1.container() != iter2.container()) return std::numeric_limits<difference_type>::max();
return (iter1.pos() - iter2.pos());
}
#include <cstring>
#include <iostream>
int main() {
struct MyStr {
MyStr(const char* str) throw() {
if(str) {
strcpy(buf, str);
len = strlen(buf);
}
}
char& operator[](const size_t idx) throw() {
static char C = '\0';
return idx >= len ? C : buf[idx];
}
const char& operator[](const size_t idx) const throw() {
static const char C = '\0';
return idx >= len ? C : buf[idx];
}
size_t size() const throw() {
return len;
}
bool empty() const throw() {
return !len;
}
size_t len = 0U;
typedef char value_type;
value_type buf[256U];
typedef GenericRAIterator<MyStr, value_type, false, true> const_iterator;
typedef GenericRAIterator<MyStr, value_type, true, true> const_reverse_iterator;
const_iterator begin() const throw() {
return std::move(const_iterator(this));
}
const_iterator end() const throw() {
const_iterator iter(this);
return std::move(iter += size()); // to past-the-end pos.
}
const_reverse_iterator rbegin() const throw() {
return std::move(const_reverse_iterator(this, true));
}
const_reverse_iterator rend() const throw() {
const_reverse_iterator iter(this, true);
return std::move(iter += size()); // to before-begin pos.
}
} myStr = "we don't need no water!";
for(const auto c : myStr) {
std::cout << c;
}
std::cout << std::endl;
auto iter = myStr.rbegin();
const auto end = myStr.rend();
for(; iter != end; ++iter) {
std::cout << *iter;
}
return 0;
}