#ifndef CHILON_ITERATOR_RANGE_HPP
#define CHILON_ITERATOR_RANGE_HPP
#include <chilon/meta/return.hpp>
// allow boost to hash these ranges
#include <boost/functional/hash/hash.hpp>
#include <iostream>
#include <iterator>
#include <string>
namespace chilon {
template <class T>
static inline auto begin(T&& t) CHILON_RETURN(std::forward<T>(t).begin())
template <class T>
static inline auto end(T&& t) CHILON_RETURN(std::forward<T>(t).end())
static inline char const * const begin(char const *str) {
return str;
}
static inline char const * end(char const *str) {
while ('\0' != *str) ++str;
return str;
}
static inline char * end(char *str) {
while ('\0' != *str) ++str;
return str;
}
/**
* @brief This class represents an iterator_range much like boost::iterator_range.
* @detailed This iterator_range provides all of the functionality of boost::iterator_range
* but in addition allows easier modification of the range through
* references for begin/end in addition to .assign
* @tparam Iterator type for iterators to begin/end of range.
*/
template <class Iterator>
struct iterator_range {
typedef typename std::iterator_traits<Iterator>::value_type value_type;
typedef typename std::iterator_traits<Iterator>::reference reference;
typedef typename std::iterator_traits<Iterator>::difference_type difference_type;
typedef typename std::iterator_traits<Iterator>::pointer pointer;
typedef typename std::iterator_traits<Iterator>::iterator_category iterator_category;
typedef Iterator iterator;
typedef Iterator const_iterator;
void assign(iterator const& begin, iterator const& end) {
begin_ = begin;
end_ = end;
}
std::size_t size() const { return end_ - begin_; }
bool empty() const { return begin_ >= end_; }
void advance() { ++begin_; }
void advance(int const size) { begin_ += size; }
bool same(char const * const ptr) const { return begin_ = ptr; }
bool end(iterator const candidate) const { return candidate == end_; }
iterator begin() const { return begin_; }
iterator end() const { return end_; }
iterator& begin() { return begin_; }
iterator& end() { return end_; }
reference front() const { return *begin_; }
reference back() const { return *(end_ - 1); }
template <class T>
friend std::ostream& operator<<(std::ostream &os, iterator_range<T> const& self);
template <class T>
bool operator==(T const& rhs) const {
return size() == rhs.size() && std::equal(begin_, end_, rhs.begin());
}
bool operator==(char const * const str) const {
return std::equal(begin_, end_, str) && str[end_ - begin_] == '\0';
}
bool operator==(std::string const &str) const {
return size() == str.size() && std::equal(begin_, end_, str.begin());
}
template <class T>
bool operator<(T const& rhs) const {
auto it = begin();
auto rhs_it = chilon::begin(rhs);
auto rhs_end = chilon::end(rhs);
for (;;) {
if (*it < *rhs_it) return true;
else if (*it != *rhs_it) return false;
else if (++rhs_it == rhs_end) return false;
else if (++it == end()) return true;
}
}
template <class T>
bool operator!=(T const& rhs) const {
return ! (*this == rhs);
}
template <class T>
void operator=(T const& rhs) {
begin_ = rhs.begin();
end_ = rhs.end();
}
reference operator[](difference_type const idx) const {
return begin_[idx];
}
// iterator_range can be converted into a string
operator std::string() const {
return std::string(begin_, end_);
}
iterator_range(iterator const& begin, iterator const& end) : begin_(begin), end_(end) {}
iterator_range(iterator const& end) : begin_(end), end_(end) {}
iterator_range(std::string const& str) : begin_(str.begin()), end_(str.end()) {}
// TODO: find default null type
iterator_range() : begin_(0), end_(0) {}
protected:
iterator begin_;
iterator end_;
};
template <class T>
std::ostream& operator<<(std::ostream &os, iterator_range<T> const& self) {
std::copy(self.begin_, self.end_,
std::ostream_iterator<typename iterator_range<T>::value_type>(os));
return os;
}
template <class T>
bool operator==(std::string const &str, iterator_range<T> const& self) {
return ! str.compare(0, str.size(), self.begin(), 0, self.size());
}
////////////////////////////////////////////////////////////////////////////////
typedef iterator_range<char const *> range;
typedef iterator_range<std::string::const_iterator> string_range;
typedef iterator_range<std::string::iterator> mutable_string_range;
static inline range to_range(char const * const str) {
return range(str, end(str));
return str;
}
template <class T>
std::size_t inline hash_value(chilon::iterator_range<T> const& arg) {
return boost::hash_range(arg.begin(), arg.end());
}
}
namespace std {
template <class T>
struct hash<chilon::iterator_range<T>> {
std::size_t operator()(chilon::iterator_range<T> const& arg) const {
return chilon::hash_value(arg);
}
};
}
#endif