diff --git a/include/uuid.h b/include/uuid.h index 69b540d..3bc0542 100644 --- a/include/uuid.h +++ b/include/uuid.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #ifdef _WIN32 #include @@ -81,14 +83,309 @@ namespace uuids struct uuid { + struct uuid_const_iterator + { + typedef uuid_const_iterator self_type; + typedef uint8_t value_type; + typedef uint8_t const & reference; + typedef uint8_t const * pointer; + typedef std::random_access_iterator_tag iterator_category; + typedef ptrdiff_t difference_type; + + protected: + pointer ptr = nullptr; + size_t index = 0; + + bool compatible(self_type const & other) const noexcept + { + return ptr == other.ptr; + } + + public: + explicit uuid_const_iterator(pointer ptr, size_t const index) : + ptr(ptr), index(index) + { + } + + uuid_const_iterator(uuid_const_iterator const & o) = default; + uuid_const_iterator& operator=(uuid_const_iterator const & o) = default; + ~uuid_const_iterator() = default; + + self_type & operator++ () + { + if (index >= uuid::state_size) + throw std::out_of_range("Iterator cannot be incremented past the end of the data."); + ++index; + return *this; + } + + self_type operator++ (int) + { + self_type tmp = *this; + ++*this; + return tmp; + } + + bool operator== (self_type const & other) const + { + assert(compatible(other)); + return index == other.index; + } + + bool operator!= (self_type const & other) const + { + return !(*this == other); + } + + reference operator* () const + { + if (ptr == nullptr) + throw std::bad_function_call(); + return *(ptr + index); + } + + reference operator-> () const + { + if (ptr == nullptr) + throw std::bad_function_call(); + return *(ptr + index); + } + + uuid_const_iterator() = default; + + self_type & operator--() + { + if (index <= 0) + throw std::out_of_range("Iterator cannot be decremented past the beginning of the data."); + --index; + return *this; + } + + self_type operator--(int) + { + self_type tmp = *this; + --*this; + return tmp; + } + + self_type operator+(difference_type offset) const + { + self_type tmp = *this; + return tmp += offset; + } + + self_type operator-(difference_type offset) const + { + self_type tmp = *this; + return tmp -= offset; + } + + difference_type operator-(self_type const & other) const + { + assert(compatible(other)); + return (index - other.index); + } + + bool operator<(self_type const & other) const + { + assert(compatible(other)); + return index < other.index; + } + + bool operator>(self_type const & other) const + { + return other < *this; + } + + bool operator<=(self_type const & other) const + { + return !(other < *this); + } + + bool operator>=(self_type const & other) const + { + return !(*this < other); + } + + self_type & operator+=(difference_type const offset) + { + if (index + offset < 0 || index + offset > uuid::state_size) + throw std::out_of_range("Iterator cannot be incremented past the end of the data."); + + index += offset; + return *this; + } + + self_type & operator-=(difference_type const offset) + { + return *this += -offset; + } + + value_type const & operator[](difference_type const offset) const + { + return (*(*this + offset)); + } + }; + + struct uuid_iterator : public uuid_const_iterator + { + typedef uuid_iterator self_type; + typedef uint8_t value_type; + typedef uint8_t& reference; + typedef uint8_t* pointer; + typedef std::random_access_iterator_tag iterator_category; + typedef ptrdiff_t difference_type; + + protected: + pointer ptr = nullptr; + size_t index = 0; + + bool compatible(self_type const & other) const noexcept + { + return ptr == other.ptr; + } + + public: + explicit uuid_iterator(pointer ptr, size_t const index) : + ptr(ptr), index(index) + { + } + + uuid_iterator(uuid_iterator const & o) = default; + uuid_iterator& operator=(uuid_iterator const & o) = default; + ~uuid_iterator() = default; + + self_type & operator++ () + { + if (index >= uuid::state_size) + throw std::out_of_range("Iterator cannot be incremented past the end of the data."); + ++index; + return *this; + } + + self_type operator++ (int) + { + self_type tmp = *this; + ++*this; + return tmp; + } + + bool operator== (self_type const & other) const + { + assert(compatible(other)); + return index == other.index; + } + + bool operator!= (self_type const & other) const + { + return !(*this == other); + } + + reference operator* () const + { + if (ptr == nullptr) + throw std::bad_function_call(); + return *(ptr + index); + } + + reference operator-> () const + { + if (ptr == nullptr) + throw std::bad_function_call(); + return *(ptr + index); + } + + uuid_iterator() = default; + + self_type & operator--() + { + if (index <= 0) + throw std::out_of_range("Iterator cannot be decremented past the beginning of the data."); + --index; + return *this; + } + + self_type operator--(int) + { + self_type tmp = *this; + --*this; + return tmp; + } + + self_type operator+(difference_type offset) const + { + self_type tmp = *this; + return tmp += offset; + } + + self_type operator-(difference_type offset) const + { + self_type tmp = *this; + return tmp -= offset; + } + + difference_type operator-(self_type const & other) const + { + assert(compatible(other)); + return (index - other.index); + } + + bool operator<(self_type const & other) const + { + assert(compatible(other)); + return index < other.index; + } + + bool operator>(self_type const & other) const + { + return other < *this; + } + + bool operator<=(self_type const & other) const + { + return !(other < *this); + } + + bool operator>=(self_type const & other) const + { + return !(*this < other); + } + + self_type & operator+=(difference_type const offset) + { + if (index + offset < 0 || index + offset > uuid::state_size) + throw std::out_of_range("Iterator cannot be incremented past the end of the data."); + + index += offset; + return *this; + } + + self_type & operator-=(difference_type const offset) + { + return *this += -offset; + } + + value_type & operator[](difference_type const offset) + { + return (*(*this + offset)); + } + + value_type const & operator[](difference_type const offset) const + { + return (*(*this + offset)); + } + }; + public: - typedef uint8_t value_type; - typedef uint8_t& reference; - typedef uint8_t const& const_reference; - typedef uint8_t* iterator; - typedef uint8_t const* const_iterator; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; + typedef uint8_t value_type; + typedef uint8_t& reference; + typedef uint8_t const& const_reference; + typedef uuid_iterator iterator; + typedef uuid_const_iterator const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static constexpr size_t state_size = 16; public: constexpr uuid() noexcept {} @@ -131,7 +428,7 @@ namespace uuids return uuid_version::none; } - constexpr std::size_t size() const noexcept { return 16; } + constexpr std::size_t size() const noexcept { return state_size; } constexpr bool nil() const noexcept { @@ -149,10 +446,10 @@ namespace uuids std::swap(lhs.data, rhs.data); } - iterator begin() noexcept { return &data[0]; } - const_iterator begin() const noexcept { return &data[0]; } - iterator end() noexcept { return &data[0] + size(); } - const_iterator end() const noexcept { return &data[0] + size(); } + iterator begin() noexcept { return uuid_iterator(&data[0], 0); } + const_iterator begin() const noexcept { return uuid_const_iterator(&data[0], 0); } + iterator end() noexcept { return uuid_iterator(&data[0], state_size); } + const_iterator end() const noexcept { return uuid_const_iterator(&data[0], state_size); } private: std::array data{ { 0 } }; diff --git a/test/test.cpp b/test/test.cpp index 024ac18..a8d7a1a 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include int main() { @@ -168,17 +169,31 @@ int main() 0x99, 0xed, 0x17, 0x7d, 0x3e, 0x43 }}; - uuid guid; - assert(guid.nil()); - - std::copy(std::cbegin(arr), std::cend(arr), std::begin(guid)); - assert(!guid.nil()); - assert(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"); - - size_t i = 0; - for (auto const & b : guid) { - assert(arr[i++] == b); + uuid guid; + assert(guid.nil()); + + std::copy(std::cbegin(arr), std::cend(arr), std::begin(guid)); + assert(!guid.nil()); + assert(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"); + + size_t i = 0; + for (auto const & b : guid) + { + assert(arr[i++] == b); + } + } + + { + const uuid guid("47183823-2574-4bfd-b411-99ed177d3e43"); + assert(!guid.nil()); + assert(uuids::to_string(guid) == "47183823-2574-4bfd-b411-99ed177d3e43"); + + size_t i = 0; + for (auto const & b : guid) + { + assert(arr[i++] == b); + } } } @@ -192,7 +207,6 @@ int main() constexpr uuid_version version = empty.version(); } - { std::cout << "Test default generator" << std::endl;