Skip to content

Instantly share code, notes, and snippets.

@FreeSlave
Last active August 18, 2016 19:15
Show Gist options
  • Save FreeSlave/397a1e06f4343df914baa9ce11205648 to your computer and use it in GitHub Desktop.
Save FreeSlave/397a1e06f4343df914baa9ce11205648 to your computer and use it in GitHub Desktop.
C++ Splitter implementation
// Copyright (c) 2016 Roman Chistokhodov
// Distributed under the Boost Software License, Version 1.0.
// http://www.boost.org/LICENSE_1_0.txt
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <utility>
#include <iterator>
template<typename SourceIterator>
struct Splitter
{
typedef typename std::iterator_traits<SourceIterator>::value_type SourceValueType;
Splitter(SourceIterator begin, SourceIterator end, const SourceValueType& delim)
: _begin(begin), _end(end), _delim(delim) {}
typedef std::pair<SourceIterator, SourceIterator> value_type;
struct iterator : public std::iterator<std::forward_iterator_tag, value_type>
{
friend struct Splitter;
private:
iterator(SourceIterator begin, SourceIterator end, const Splitter* splitter)
: _range(begin, end), _splitter(splitter) {
_atEnd = begin == end && end == splitter->_end;
}
public:
const value_type& operator*() const {
return _range;
}
const value_type* operator->() const {
return &_range;
}
iterator& operator++() {
forward();
return *this;
}
iterator operator++(int) {
iterator toReturn = *this;
forward();
return toReturn;
}
bool operator==(const iterator& other) const {
return equal(other);
}
bool operator!=(const iterator& other) const {
return !equal(other);
}
private:
void forward() {
if (_atEnd) {
return;
}
if (_range.second != _splitter->_end) {
_range.first = ++_range.second;
_range.second = std::find(_range.first, _splitter->_end, _splitter->_delim);
} else {
_range.first = _range.second;
_atEnd = true;
}
}
bool equal(const iterator& other) const {
return this->_range == other._range && this->_atEnd == other._atEnd;
}
std::pair<SourceIterator, SourceIterator> _range;
const Splitter* _splitter;
bool _atEnd;
};
iterator begin() const {
return iterator(_begin, std::find(_begin, _end, _delim), this);
}
iterator end() const {
return iterator(_end, _end, this);
}
private:
SourceIterator _begin;
SourceIterator _end;
SourceValueType _delim;
};
template<typename SourceIterator>
std::vector<std::string> applySplitter(SourceIterator begin, SourceIterator end)
{
typedef Splitter<SourceIterator> SplitterType;
SplitterType splitter(begin, end, ':');
typename SplitterType::iterator it = splitter.begin();
std::vector<std::string> toReturn;
while(it != splitter.end()) {
toReturn.push_back(std::string(it->first, it->second));
++it;
}
return toReturn;
}
void splitter_concept_test()
{
typedef Splitter<const char*> SplitterType;
const char* cstr = "one:two";
SplitterType splitter(cstr, cstr + strlen(cstr), ':');
assert(splitter.begin() == splitter.begin());
assert(splitter.end() == splitter.end());
assert(splitter.begin() != splitter.end());
SplitterType::iterator it = splitter.begin();
assert(std::string(it->first, it->second) == "one");
assert(splitter.begin() == it++);
assert(splitter.begin() != it);
assert(std::string(it->first, it->second) == "two");
assert(++it == splitter.end());
}
void splitter_test()
{
std::vector<std::string> vec;
vec.push_back("one");
vec.push_back("two");
vec.push_back("three");
const char* cstr = "one:two:three";
assert(applySplitter(cstr, cstr + strlen(cstr)) == vec);
std::string str(cstr);
assert(applySplitter(str.begin(), str.end()) == vec);
std::vector<std::string> singleItemVector;
singleItemVector.push_back("one");
cstr = "one";
assert(applySplitter(cstr, cstr + strlen(cstr)) == singleItemVector);
str = cstr;
assert(applySplitter(str.begin(), str.end()) == singleItemVector);
std::vector<std::string> emptyVec;
cstr = "";
assert(applySplitter(cstr, cstr + strlen(cstr)) == emptyVec);
str = cstr;
assert(applySplitter(str.begin(), str.end()) == emptyVec);
std::vector<std::string> vecWithSpaces;
vecWithSpaces.push_back("");
vecWithSpaces.push_back("one");
vecWithSpaces.push_back("");
vecWithSpaces.push_back("two");
vecWithSpaces.push_back("");
cstr = ":one::two:";
assert(applySplitter(cstr, cstr + strlen(cstr)) == vecWithSpaces);
str = cstr;
assert(applySplitter(str.begin(), str.end()) == vecWithSpaces);
}
int main(int argc, char** argv)
{
splitter_test();
splitter_concept_test();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment