Skip to content

Instantly share code, notes, and snippets.

@oskaritimperi
Last active January 4, 2016 19:39
Show Gist options
  • Select an option

  • Save oskaritimperi/8668788 to your computer and use it in GitHub Desktop.

Select an option

Save oskaritimperi/8668788 to your computer and use it in GitHub Desktop.
#ifndef STRINGREF_H
#define STRINGREF_H
#include <string>
#include <algorithm>
template<class StringT>
class BasicStringRef
{
public:
typedef StringT basic_string;
typedef typename basic_string::size_type size_type;
typedef typename basic_string::value_type value_type;
BasicStringRef() :
m_begin(0),
m_end(0)
{}
BasicStringRef(const BasicStringRef &other) :
m_begin(other.m_begin),
m_end(other.m_end)
{}
BasicStringRef(const basic_string &s) :
m_begin(s.data()),
m_end(s.data()+s.size())
{}
BasicStringRef(const value_type *begin, const value_type *end) :
m_begin(begin),
m_end(end)
{}
BasicStringRef(const value_type *str, size_type size) :
m_begin(str),
m_end(str+size)
{}
BasicStringRef(const value_type *str) :
m_begin(str),
m_end(str)
{
while (*m_end++) ;
m_end--;
}
BasicStringRef &operator=(BasicStringRef other)
{
swap(*this, other);
return *this;
}
void swap(BasicStringRef &lhs, BasicStringRef &rhs)
{
std::swap(lhs.m_begin, rhs.m_begin);
std::swap(lhs.m_end, rhs.m_end);
}
size_type size() const
{
return m_end - m_begin;
}
BasicStringRef substr(size_type pos = 0, size_type count = basic_string::npos) const
{
if (pos > size())
return BasicStringRef();
const value_type *begin = m_begin + pos;
if (count == basic_string::npos)
count = size() - pos;
if (pos+count > size())
count = size() - pos;
return BasicStringRef(begin, count);
}
size_type find(const value_type *s, size_type pos, size_type count) const
{
if (count == 0)
return pos;
if (pos >= size() || size() == 0)
return basic_string::npos;
const value_type *p = std::search(m_begin, m_end, s, s+count);
if (p != m_end)
return p - m_begin;
return basic_string::npos;
}
size_type find(const basic_string &str, size_type pos = 0) const
{
return find(str.c_str(), pos, str.size());
}
size_type find(const value_type *s, size_type pos = 0) const
{
if (pos >= size() || size() == 0)
return basic_string::npos;
const value_type *tmp = s;
while (*tmp++) ;
return find(s, pos, tmp-s-1);
}
size_type find(value_type ch, size_type pos = 0) const
{
return find(&ch, pos, 1);
}
size_type find_first_of(const value_type *s, size_type pos, size_type count) const
{
if (pos >= size())
return basic_string::npos;
const value_type *p = std::find_first_of(m_begin+pos, m_end, s, s+count);
if (p == m_end)
return basic_string::npos;
return p - m_begin;
}
size_type find_first_of(const basic_string &str, size_type pos = 0) const
{
return find_first_of(str.c_str(), pos, str.size());
}
size_type find_first_of(const value_type *s, size_type pos = 0) const
{
if (pos >= size() || size() == 0)
return basic_string::npos;
const value_type *tmp = s;
while (*tmp++) ;
return find_first_of(s, pos, tmp-s-1);
}
size_type find_first_of(value_type ch, size_type pos = 0) const
{
return find_first_of(&ch, pos, 1);
}
size_type find_first_not_of(const basic_string &str, size_type pos = 0) const
{
return find_first_not_of(str.c_str(), pos, str.size());
}
size_type find_first_not_of(const value_type *s, size_type pos, size_type count) const
{
if (pos >= size() || count == 0)
return basic_string::npos;
for (; pos < size(); ++pos)
{
if (std::find(s, s+count, *(m_begin+pos)) == s+count)
{
return pos;
}
}
return basic_string::npos;
}
size_type find_first_not_of(const value_type *s, size_type pos = 0) const
{
if (pos >= size() || size() == 0)
return basic_string::npos;
const value_type *tmp = s;
while (*tmp++) ;
return find_first_not_of(s, pos, tmp-s-1);
}
size_type find_first_not_of(value_type ch, size_type pos = 0) const
{
return find_first_not_of(&ch, pos, 1);
}
size_type find_last_of(const value_type *s, size_type pos, size_type count) const
{
if (size() == 0 || count == 0)
return basic_string::npos;
size_type size = this->size();
if (--size > pos)
size = pos;
do
{
if (std::find(s, s+count, *(m_begin+size)) != s+count)
return size;
}
while (size-- != 0);
return basic_string::npos;
}
size_type find_last_of(const value_type *s, size_type pos = basic_string::npos) const
{
const value_type *tmp = s;
while (*tmp++) ;
return find_last_of(s, pos, tmp-s-1);
}
size_type find_last_of(const basic_string &s, size_type pos = basic_string::npos) const
{
return find_last_of(s.c_str(), pos, s.size());
}
size_type find_last_of(value_type ch, size_type pos = basic_string::npos) const
{
return find_last_of(&ch, pos, 1);
}
size_type find_last_not_of(const value_type *s, size_type pos, size_type count) const
{
if (size() == 0 || count == 0)
return basic_string::npos;
size_type size = this->size();
if (--size > pos)
size = pos;
do
{
if (std::find(s, s+count, *(m_begin+size)) == s+count)
return size;
}
while (size-- != 0);
return basic_string::npos;
}
size_type find_last_not_of(const value_type *s, size_type pos = basic_string::npos) const
{
const value_type *tmp = s;
while (*tmp++) ;
return find_last_not_of(s, pos, tmp-s-1);
}
size_type find_last_not_of(const basic_string &s, size_type pos = basic_string::npos) const
{
return find_last_not_of(s.c_str(), pos, s.size());
}
size_type find_last_not_of(value_type ch, size_type pos = basic_string::npos) const
{
return find_last_not_of(&ch, pos, 1);
}
operator basic_string() const
{
return to_string();
}
basic_string to_string() const
{
return basic_string(m_begin, m_end);
}
template<class ContainerT>
void split(ContainerT &values, const basic_string &delims,
size_type max_split = basic_string::npos, bool trim_empty = false)
{
size_type pos, last_pos = 0;
while (true)
{
pos = find_first_of(delims, last_pos);
if (pos == basic_string::npos)
{
pos = size();
if (pos != last_pos || !trim_empty)
values.push_back(typename ContainerT::value_type(m_begin+last_pos, pos-last_pos));
break;
}
else
{
if (pos != last_pos || !trim_empty)
{
values.push_back(typename ContainerT::value_type(m_begin+last_pos, pos-last_pos));
if (max_split != basic_string::npos && values.size() == max_split)
{
values.push_back(typename ContainerT::value_type(m_begin+pos+1, size()-pos-1));
break;
}
}
}
last_pos = pos+1;
}
}
BasicStringRef lstrip(const basic_string &chars)
{
if (size() == 0)
return *this;
size_type i = find_first_not_of(chars);
if (i != basic_string::npos)
return BasicStringRef(m_begin+i, m_end);
return BasicStringRef();
}
BasicStringRef rstrip(const basic_string &chars)
{
if (size() == 0)
return *this;
size_type i = find_last_not_of(chars);
if (i != basic_string::npos)
return BasicStringRef(m_begin, m_begin+i+1);
return BasicStringRef();
}
BasicStringRef strip(const basic_string &chars)
{
return lstrip(chars).rstrip(chars);
}
bool starts_with(const basic_string &prefix)
{
if (prefix.size() > size())
return false;
return std::equal(m_begin, m_begin+prefix.size(), prefix.begin());
}
bool ends_with(const basic_string &suffix)
{
if (suffix.size() > size())
return false;
return std::equal(m_end-suffix.size(), m_end, suffix.begin());
}
private:
const value_type *m_begin;
const value_type *m_end;
};
typedef BasicStringRef<std::string> StringRef;
#endif // STRINGREF_H
#include "stringref.h"
#include "gtest/gtest.h"
static const char *s = "The quick brown fox jumps over the lazy dog";
static const std::string ss = s;
static const size_t s_len = 43;
static const char *s2 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut";
static const std::string ss2 = s2;
static const size_t s2_len = 93;
TEST(StringRef, default_constructor)
{
StringRef ref;
ASSERT_EQ(0, (int) ref.size());
}
TEST(StringRef, copy_constructor)
{
StringRef ref1(s);
StringRef ref2(ref1);
ASSERT_EQ(s_len, ref1.size());
ASSERT_EQ(s_len, ref2.size());
ASSERT_STREQ(s, ((std::string)ref1).c_str());
ASSERT_STREQ(s, ((std::string)ref2).c_str());
}
TEST(StringRef, std_string_constructor)
{
StringRef ref(ss);
ASSERT_EQ(s_len, ref.size());
ASSERT_STREQ(s, ((std::string)ref).c_str());
}
TEST(StringRef, charp_count_constructor)
{
StringRef ref(s, 9);
ASSERT_EQ(9, (int) ref.size());
ASSERT_STREQ("The quick", ((std::string)ref).c_str());
}
TEST(StringRef, charp_constructor)
{
StringRef ref(s);
ASSERT_EQ(s_len, ref.size());
ASSERT_STREQ(s, ((std::string)ref).c_str());
}
TEST(StringRef, assignment)
{
StringRef ref1(s);
ASSERT_EQ(s_len, ref1.size());
ASSERT_STREQ(s, ref1.to_string().c_str());
StringRef ref2;
ASSERT_EQ(0, (int) ref2.size());
ref2 = ref1;
ASSERT_EQ(s_len, ref2.size());
ASSERT_STREQ(s, ref2.to_string().c_str());
}
TEST(StringRef, swap)
{
StringRef ref1(s, s_len);
ASSERT_EQ(s_len, ref1.size());
StringRef ref2(s2, s2_len);
ASSERT_EQ(s2_len, ref2.size());
ref1.swap(ref1, ref2);
ASSERT_EQ(s_len, ref2.size());
ASSERT_EQ(s2_len, ref1.size());
}
TEST(StringRef, size)
{
StringRef ref1;
ASSERT_EQ(0, (int) ref1.size());
StringRef ref2(s, s_len);
ASSERT_EQ(s_len, ref2.size());
StringRef ref3(s2);
ASSERT_EQ(s2_len, ref3.size());
}
TEST(StringRef, substr)
{
StringRef ref1(s, s_len);
StringRef subref11 = ref1.substr();
ASSERT_EQ(s_len, subref11.size());
StringRef subref12 = ref1.substr(4);
ASSERT_STREQ("quick brown fox jumps over the lazy dog", subref12.to_string().c_str());
StringRef subref13 = ref1.substr(4, 5);
ASSERT_EQ(5, (int) subref13.size());
ASSERT_STREQ("quick", subref13.to_string().c_str());
StringRef subref14 = ref1.substr(0, s_len+10);
ASSERT_EQ(s_len, subref14.size());
StringRef subref15 = ref1.substr(4, s_len+10);
ASSERT_STREQ("quick brown fox jumps over the lazy dog", subref15.to_string().c_str());
StringRef subref16 = ref1.substr(s_len+10, 5);
ASSERT_EQ(0, (int) subref16.size());
}
TEST(StringRef, find_std_str)
{
StringRef ref1(s, s_len);
StringRef::size_type i = ref1.find(std::string("brown"));
ASSERT_EQ(10, (int) i);
StringRef ref2(s+15);
i = ref2.find(std::string("brown"));
ASSERT_EQ(std::string::npos, i);
}
TEST(StringRef, find_charp_pos_count)
{
StringRef ref(s, s_len);
StringRef::size_type i = ref.find("fox", 0, 3);
ASSERT_EQ(16, (int) i);
i = ref.find("jumps", i, 5);
ASSERT_EQ(20, (int) i);
i = ref.find("foobar", i, 6);
ASSERT_EQ(std::string::npos, i);
}
TEST(StringRef, find_char_pos)
{
StringRef ref(s, s_len);
size_t i = ref.find('g');
ASSERT_EQ((size_t)42, i);
i = ref.find('\n');
ASSERT_EQ(std::string::npos, i);
}
TEST(StringRef, split)
{
std::vector<std::string> correct;
correct.push_back("The");
correct.push_back("quick");
correct.push_back("brown");
correct.push_back("fox");
correct.push_back("jumps");
correct.push_back("over");
correct.push_back("the");
correct.push_back("lazy");
correct.push_back("dog");
StringRef ref(s, s_len);
std::vector<std::string> strings;
ref.split(strings, " ");
ASSERT_EQ(correct.size(), strings.size());
for (size_t i = 0; i < correct.size(); ++i)
{
ASSERT_STREQ(correct[i].c_str(), strings[i].c_str());
}
std::vector<StringRef> refs;
ref.split(refs, " ");
ASSERT_EQ(refs.size(), correct.size());
for (size_t i = 0; i < correct.size(); ++i)
{
ASSERT_STREQ(correct[i].c_str(), refs[i].to_string().c_str());
}
}
TEST(StringRef, split_w_max_split)
{
std::string a = "foo bar foo yeah";
StringRef ref(a);
std::vector<StringRef> refs;
ref.split(refs, " ", 1);
ASSERT_EQ((size_t)2, refs.size());
ASSERT_STREQ("foo", refs[0].to_string().c_str());
ASSERT_STREQ("bar foo yeah", refs[1].to_string().c_str());
refs.clear();
ref.split(refs, " ", 2);
ASSERT_EQ((size_t)3, refs.size());
ASSERT_STREQ("foo", refs[0].to_string().c_str());
ASSERT_STREQ("bar", refs[1].to_string().c_str());
ASSERT_STREQ("foo yeah", refs[2].to_string().c_str());
}
TEST(StringRef, split_trim_empty)
{
std::string a = "foo bar yeah";
StringRef refa(a);
std::vector<StringRef> refs;
refa.split(refs, " ", std::string::npos, true);
ASSERT_EQ((size_t)3, refs.size());
refs.clear();
std::string b = "foo bar yeah";
StringRef refb(b);
refb.split(refs, " ", std::string::npos, true);
ASSERT_EQ((size_t)3, refs.size());
refs.clear();
refb.split(refs, " ", std::string::npos, false);
ASSERT_EQ((size_t)4, refs.size());
refs.clear();
refb.split(refs, " ", 2, false);
ASSERT_EQ((size_t)3, refs.size());
ASSERT_STREQ(" yeah", refs[refs.size()-1].to_string().c_str());
}
TEST(StringRef, split_max_split_last_split_until_end_of_orig_str)
{
std::string a = "this is some text\n";
StringRef ref(a.c_str(), a.size()-1);
std::vector<StringRef> tokens;
ref.split(tokens, " ", 2);
ASSERT_EQ((size_t)3, tokens.size());
ASSERT_STREQ("this", tokens[0].to_string().c_str());
ASSERT_STREQ("is", tokens[1].to_string().c_str());
ASSERT_STREQ("some text", tokens[2].to_string().c_str());
}
TEST(StringRef, lstrip)
{
const char *a = "foobar ";
StringRef aref(a);
aref = aref.lstrip(" ");
ASSERT_EQ(strlen(a), aref.size());
ASSERT_STREQ(a, aref.to_string().c_str());
const char *b = " foobar";
StringRef bref(b);
bref = bref.lstrip(" ");
ASSERT_EQ(strlen(b)-2, bref.size());
ASSERT_STREQ("foobar", bref.to_string().c_str());
const char *c = "";
StringRef cref(c);
cref = cref.lstrip(" ");
ASSERT_EQ((size_t)0, cref.size());
const char *d = " ";
StringRef dref(d);
dref = dref.lstrip(" ");
ASSERT_EQ((size_t)0, dref.size());
const char *e = " foobar ";
StringRef eref(e);
eref = eref.lstrip(" ");
ASSERT_EQ((size_t)11, eref.size());
}
TEST(StringRef, rstrip)
{
const char *a = " foobar";
StringRef aref(a);
aref = aref.rstrip(" ");
ASSERT_EQ(strlen(a), aref.size());
ASSERT_STREQ(a, aref.to_string().c_str());
const char *b = "foobar ";
StringRef bref(b);
bref = bref.rstrip(" ");
ASSERT_EQ(strlen(b)-2, bref.size());
ASSERT_STREQ("foobar", bref.to_string().c_str());
const char *c = "";
StringRef cref(c);
cref = cref.rstrip(" ");
ASSERT_EQ((size_t)0, cref.size());
const char *d = " ";
StringRef dref(d);
dref = dref.rstrip(" ");
ASSERT_EQ((size_t)0, dref.size());
const char *e = " foobar ";
StringRef eref(e);
eref = eref.rstrip(" ");
ASSERT_EQ((size_t)10, eref.size());
}
TEST(StringRef, strip)
{
const char *a = " foobar";
StringRef aref(a);
aref = aref.strip(" ");
ASSERT_EQ((size_t)6, aref.size());
ASSERT_STREQ("foobar", aref.to_string().c_str());
const char *b = "foobar ";
StringRef bref(b);
bref = bref.strip(" ");
ASSERT_EQ((size_t)6, bref.size());
ASSERT_STREQ("foobar", bref.to_string().c_str());
const char *c = "";
StringRef cref(c);
cref = cref.strip(" ");
ASSERT_EQ((size_t)0, cref.size());
const char *d = " ";
StringRef dref(d);
dref = dref.strip(" ");
ASSERT_EQ((size_t)0, dref.size());
const char *e = " foobar ";
StringRef eref(e);
eref = eref.strip(" ");
ASSERT_EQ((size_t)6, eref.size());
ASSERT_STREQ("foobar", eref.to_string().c_str());
}
TEST(StringRef, starts_with)
{
const char *a = "foobar baz";
StringRef aref(a);
ASSERT_TRUE(aref.starts_with("foo"));
ASSERT_TRUE(aref.starts_with("foobar"));
ASSERT_TRUE(aref.starts_with("foobar baz"));
ASSERT_FALSE(aref.starts_with("fob"));
ASSERT_FALSE(aref.starts_with("foobar bazz"));
}
TEST(StringRef, ends_with)
{
const char *a = "foobar baz";
StringRef aref(a);
ASSERT_TRUE(aref.ends_with("baz"));
ASSERT_TRUE(aref.ends_with("foobar baz"));
ASSERT_FALSE(aref.ends_with("zab"));
ASSERT_FALSE(aref.ends_with(" foobar baz"));
}
TEST(StringRef, find_first_of)
{
StringRef ref1(s, s_len);
size_t i1 = ref1.find_first_of("lazy", 0, 4);
size_t i2 = ref1.find_first_of("azyl", 0, 4);
size_t i3 = ref1.find_first_of("zyla", 0, 4);
size_t i4 = ref1.find_first_of("ylaz", 0, 4);
ASSERT_EQ((size_t)35, i1);
ASSERT_EQ(i1, i2);
ASSERT_EQ(i1, i3);
ASSERT_EQ(i1, i4);
}
TEST(StringRef, find_first_not_of)
{
const char *a = " foobar ";
StringRef ref(a);
size_t i = ref.find_first_not_of(" ", 0, 1);
ASSERT_EQ((size_t)2, i);
i = ref.find_first_not_of("fobar ", 0, 6);
ASSERT_EQ(std::string::npos, i);
}
TEST(StringRef, find_last_of)
{
// The quick brown
StringRef ref(s, 15);
size_t i = ref.find_last_of("k ", std::string::npos, 2);
ASSERT_EQ((size_t)9, i);
i = ref.find_last_of("brown", std::string::npos, 5);
ASSERT_EQ((size_t)14, i);
i = ref.find_last_of("T", std::string::npos, 1);
ASSERT_EQ((size_t)0, i);
i = ref.find_last_of("\t", std::string::npos, 1);
ASSERT_EQ(std::string::npos, i);
i = ref.find_last_of("quick", 3, 5);
ASSERT_EQ(std::string::npos, i);
}
TEST(StringRef, find_last_not_of)
{
// The quick brown
StringRef ref(s, 15);
size_t i;
i = ref.find_last_not_of(" ", std::string::npos, 1);
ASSERT_EQ((size_t)14, i);
i = ref.find_last_not_of(" n", std::string::npos, 2);
ASSERT_EQ((size_t)13, i);
i = ref.find_last_not_of("brown", std::string::npos, 5);
ASSERT_EQ((size_t)9, i);
i = ref.find_last_not_of("T", std::string::npos, 1);
ASSERT_EQ((size_t)14, i);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment