Implement string view (with bot limited functionality)

This commit is contained in:
Arun M 2017-10-31 19:34:21 +05:30
parent 6a7d2d69c0
commit 063a0af131
6 changed files with 790 additions and 0 deletions

View file

@ -0,0 +1,248 @@
#ifndef JWT_STRING_VIEW_IPP
#define JWT_STRING_VIEW_IPP
namespace jwt {
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find(
const CharT* str,
size_type pos,
size_type n) const noexcept -> size_type
{
assert (str);
assert (n < (len_ - pos) && "Comparison size out of bounds");
if (n == 0) {
return pos <= len_ ? pos : npos;
}
if (n <= len_) {
for (; pos <= (len_ - n); ++pos) {
if (traits_type::eq(data_[pos], str[0]) &&
traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) {
return pos;
}
}
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::rfind(
const CharT* str,
size_type pos,
size_type n) const noexcept -> size_type
{
assert (str);
assert (pos < len_ && "Position out of bounds");
if (n <= len_) {
pos = std::min(len_ - n, pos);
do {
if (traits_type::eq(data_[pos], str[0]) &&
traits_type::compare(data_ + pos + 1, str + 1, n - 1) == 0) {
return pos;
}
} while (pos-- != 0);
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find(
const CharT ch,
size_type pos) const noexcept -> size_type
{
if (pos < len_) {
for (size_type i = pos; i < len_; ++i) {
if (traits_type::eq(data_[i], ch)) return i;
}
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::rfind(
const CharT ch,
size_type pos) const noexcept -> size_type
{
if (pos < len_) {
do {
if (traits_type::eq(data_[pos], ch)) {
return pos;
}
} while (pos-- != 0);
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_first_of(
const CharT* str,
size_type pos,
size_type count) const noexcept -> size_type
{
assert (str);
for (size_type i = pos; i < len_; ++i) {
auto p = traits_type::find(str, count, data_[i]);
if (p) {
return i;
}
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_last_of(
const CharT* str,
size_type pos,
size_type count) const noexcept -> size_type
{
assert (str);
assert (pos < len_ && "Position must be within the bounds of the view");
size_type siz = len_;
if (siz && count) {
siz = std::min(pos, siz);
do {
auto p = traits_type::find(str, count, data_[siz]);
if (p) {
return siz;
}
} while (siz-- != 0);
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_first_not_of(
const CharT* str,
size_type pos,
size_type n) const noexcept -> size_type
{
assert (str);
assert (pos < len_&& "Position must be within the bounds of the view");
for (size_type i = pos; i < len_; ++i)
{
auto p = traits_type::find(str, n, data_[i]);
if (not p) return i;
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_last_not_of(
const CharT* str,
size_type pos,
size_type n) const noexcept -> size_type
{
assert (str);
assert (pos < len_ && "Position must be within the bounds of the view");
do {
for (size_type i = 0; i < n; ++i) {
if (not traits_type::eq(data_[pos], str[i])) return pos;
}
} while (pos-- != 0);
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_first_not_of(
CharT ch,
size_type pos) const noexcept -> size_type
{
assert (pos < len_&& "Position must be within the bounds of the view");
for (size_type i = pos; i < len_; ++i) {
if (not traits_type::eq(data_[i], ch)) return i;
}
return npos;
}
template <typename CharT, typename Traits>
auto basic_string_view<CharT, Traits>::find_last_not_of(
CharT ch,
size_type pos) const noexcept -> size_type
{
assert (pos < len_ && "Position must be within the bounds of the view");
do {
if (not traits_type::eq(data_[pos], ch)) return pos;
} while (pos-- != 0);
return npos;
}
// Comparison Operators
template <typename CharT, typename Traits>
bool operator== (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
if (a.length() != b.length()) return false;
using traits_type = typename basic_string_view<CharT, Traits>::traits_type;
using size_type = typename basic_string_view<CharT, Traits>::size_type;
for (size_type i = 0; i < a.length(); ++i) {
if (not traits_type::eq(a[i], b[i])) return false;
}
return true;
}
template <typename CharT, typename Traits>
bool operator!= (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
return not ( a == b );
}
template <typename CharT, typename Traits>
bool operator< (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
return a.compare(b) < 0;
}
template <typename CharT, typename Traits>
bool operator> (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
return a.compare(b) > 0;
}
template <typename CharT, typename Traits>
bool operator<= (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
return a.compare(b) <= 0;
}
template <typename CharT, typename Traits>
bool operator>= (basic_string_view<CharT, Traits> a,
basic_string_view<CharT, Traits> b) noexcept
{
return a.compare(b) >= 0;
}
template <typename CharT, typename Traits>
std::ostream& operator<< (std::ostream& os, basic_string_view<CharT, Traits> sv)
{
os.write(sv.data(), sv.length());
return os;
}
} // END namespace jwt
#endif

24
include/jwt/jwt.hpp Normal file
View file

@ -0,0 +1,24 @@
#ifndef JWT_HPP
#define JWT_HPP
namespace jwt {
enum class algorithm
{
NONE = 0,
HS256,
HS384,
HS512,
RS256,
RS384,
RS512,
ES256,
ES384,
ES512,
TERM,
};
} // END namespace jwt
#endif

349
include/jwt/string_view.hpp Normal file
View file

@ -0,0 +1,349 @@
#ifndef JWT_STRING_VIEW_HPP
#define JWT_STRING_VIEW_HPP
#include <limits>
#include <string>
#include <cassert>
namespace jwt {
/*
* Implements c++17 string_view.
* Could have used boost::string_ref, but wanted to
* keep boost dependency off from this library.
*/
template <
typename CharT,
typename Traits = std::char_traits<CharT>
>
class basic_string_view
{
public: // Member Types
using traits_type = std::char_traits<CharT>;
using value_type = CharT;
using pointer = const CharT*;
using const_pointer = const CharT*;
using reference = const CharT&;
using const_reference = const CharT&;
using iterator = const CharT*;
using const_iterator = const CharT*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
static constexpr size_type npos = size_type(-1);
public: // 'tors
/// The default constructor;
basic_string_view() = default;
/// Construct from string literal
basic_string_view(const CharT* str) noexcept
: data_(str)
, len_(str ? traits_type::length(str) : 0)
{
}
/// Construct from CharT pointer and provided length
basic_string_view(const CharT* p, size_type len) noexcept
: data_(p)
, len_(len)
{
}
/// Construct from std::string
template <typename Allocator>
basic_string_view(
const std::basic_string<CharT, Traits, Allocator>& str) noexcept
: data_(str.data())
, len_(str.length())
{
}
/// Copy constructor
basic_string_view(const basic_string_view&) = default;
/// Assignment operator
basic_string_view& operator=(const basic_string_view&) = default;
/// Destructor
~basic_string_view()
{
data_ = nullptr;
len_ = 0;
}
public: // Exposed APIs
/// Iterator Member Functions
iterator begin() const noexcept { return data_; }
iterator end() const noexcept { return data_ + len_; }
iterator rbegin() const noexcept { return reverse_iterator(end()); }
iterator rend() const noexcept { return reverse_iterator(begin()); }
const_iterator cbegin() const noexcept { return begin(); }
const_iterator cend() const noexcept { return end(); }
const_iterator crbegin() const noexcept { return rbegin(); }
const_iterator crend() const noexcept { return rend(); }
/// Capacity Member Functions
size_type length() const noexcept { return len_; }
size_type size() const noexcept { return len_; }
size_type max_size() const noexcept
{
return (npos - sizeof(size_type) - sizeof(void*))
/ sizeof(value_type) / 4;
}
bool empty() const noexcept { return len_ == 0; }
/// Element Access Member Functions
const_reference operator[](size_type idx) const noexcept
{
return data_[idx];
}
// NOTE: 'at' not supported
//CharT at(size_type idx) const;
const_reference front() const noexcept
{
return data_[0];
}
const_reference back() const noexcept
{
return data_[len_ - 1];
}
const_pointer data() const noexcept
{
return data_;
}
/// Modifier Member Functions
void remove_prefix(size_type n) noexcept
{
assert (n < len_ && "Data would point out of bounds");
data_ += n;
len_ -= n;
}
void remove_suffix(size_type n) noexcept
{
assert (n < len_ && "Suffix length more than data length");
len_ -= n;
}
void swap(basic_string_view& other)
{
std::swap(data_, other.data_);
std::swap(len_, other.len_);
}
/// String Operation Member Functions
template <typename Allocator>
explicit operator std::basic_string<CharT, Traits, Allocator>() const
{
return {data_, len_};
}
template <typename Allocator = std::allocator<CharT>>
std::basic_string<CharT, Traits, Allocator>
to_string(const Allocator& alloc = Allocator()) const
{
return {data_, len_, alloc};
}
// NOTE: Does not throw
size_type copy(CharT* dest, size_type n, size_type pos = 0) const noexcept
{
assert (pos < len_ && n < len_);
size_type to_copy = std::min(n, len_ - pos);
for (size_type i = 0; i < to_copy; i++) {
dest[i] = data_[i + pos];
}
return to_copy;
}
// NOTE: Does not throw
basic_string_view substr(size_type pos, size_type n = npos) const noexcept
{
assert (pos < len_ && "Start position should be less than length of the view");
assert (n == npos ? 1 : (n - pos) < len_ &&
"Substring length asked for is more than the view length");
if (n == npos) n = len_;
return basic_string_view{data_ + pos, n};
}
/// Comparison Member Functions
int compare(const basic_string_view& other) const noexcept
{
int ret = traits_type::compare(data_, other.data_, std::min(len_, other.len_));
if (ret == 0) {
ret = compare_length(len_, other.len_);
}
return ret;
}
int compare(size_type pos, size_type n, basic_string_view other) const noexcept
{
return substr(pos, n).compare(other);
}
int compare(const CharT* str) const noexcept
{
return compare(basic_string_view{str});
}
int compare(size_type pos, size_type n, const CharT* str) const noexcept
{
return compare(pos, n, basic_string_view{str});
}
int compare(size_type pos, size_type n1, const CharT* str, size_type n2) const noexcept
{
return compare(pos, n1, basic_string_view{str, n2});
}
/// Find operations
size_type find(const CharT* str, size_type pos, size_type n) const noexcept;
size_type find(const CharT ch, size_type pos) const noexcept;
size_type find(basic_string_view sv, size_type pos = 0) const noexcept
{
return find(sv.data(), pos, sv.length());
}
size_type find(const CharT* str, size_type pos = 0) const noexcept
{
return find(str, pos, traits_type::length(str));
}
size_type rfind(const CharT* str, size_type pos, size_type n) const noexcept;
size_type rfind(const CharT ch, size_type pos) const noexcept;
size_type rfind(basic_string_view sv, size_type pos = 0) const noexcept
{
return rfind(sv.data(), pos, sv.length());
}
size_type rfind(const CharT* str, size_type pos = 0) const noexcept
{
return rfind(str, pos, traits_type::length(str));
}
size_type find_first_of(const CharT* str, size_type pos, size_type count) const noexcept;
size_type find_first_of(basic_string_view str, size_type pos = 0) const noexcept
{
return find_first_of(str.data(), pos, str.length());
}
size_type find_first_of(CharT ch, size_type pos = 0) const noexcept
{
return find(ch, pos);
}
size_type find_first_of(const CharT* str, size_type pos = 0) const noexcept
{
return find_first_of(str, pos, traits_type::length(str));
}
size_type find_last_of(const CharT* str, size_type pos, size_type count) const noexcept;
size_type find_last_of(basic_string_view str, size_type pos = npos) const noexcept
{
return find_last_of(str.data(), (pos == npos ? len_ - 1 : pos), str.length());
}
size_type find_last_of(CharT ch, size_type pos = npos) const noexcept
{
return rfind(ch, pos == npos ? len_ - 1 : pos);
}
size_type find_last_of(const CharT* str, size_type pos = npos) const noexcept
{
return find_last_of(str, (pos == npos ? len_ - 1 : pos), traits_type::length(str));
}
size_type find_first_not_of(const CharT* str, size_type pos, size_type n) const noexcept;
size_type find_first_not_of(CharT ch, size_type pos) const noexcept;
size_type find_first_not_of(basic_string_view str, size_type pos = 0) const noexcept
{
return find_first_not_of(str.data(), pos, str.length());
}
size_type find_first_not_of(const CharT* str, size_type pos = 0) const noexcept
{
return find_first_not_of(str, pos, traits_type::length(str));
}
size_type find_last_not_of(const CharT* str, size_type pos, size_type n) const noexcept;
size_type find_last_not_of(CharT ch, size_type pos) const noexcept;
size_type find_last_not_of(basic_string_view str, size_type pos = npos) const noexcept
{
return find_last_not_of(str.data(), (pos == npos ? len_ - 1 : pos), str.length());
}
size_type find_last_not_of(const CharT* str, size_type pos = npos) const noexcept
{
return find_last_not_of(str, (pos == npos ? len_ - 1 : pos), traits_type::length(str));
}
/// Comparison operators Member Functions
/*
friend bool operator== (basic_string_view a, basic_string_view b) noexcept;
friend bool operator!= (basic_string_view a, basic_string_view b) noexcept;
friend bool operator< (basic_string_view a, basic_string_view b) noexcept;
friend bool operator> (basic_string_view a, basic_string_view b) noexcept;
friend bool operator<= (basic_string_view a, basic_string_view b) noexcept;
friend bool operator>= (basic_string_view a, basic_string_view b) noexcept;
*/
private: // private implementations
static constexpr int compare_length(size_type n1, size_type n2) noexcept
{
return static_cast<difference_type>(n1 - n2) > std::numeric_limits<int>::max()
? std::numeric_limits<int>::max()
: static_cast<difference_type>(n1 - n2) < std::numeric_limits<int>::min()
? std::numeric_limits<int>::min()
: static_cast<int>(n1 - n2)
;
}
private:
// This is what view is basically...
const char* data_ = nullptr;
size_type len_ = 0;
};
} // END namespace jwt
#include "jwt/impl/string_view.ipp"
#endif

BIN
include/jwt/test_sv Executable file

Binary file not shown.

169
include/jwt/test_sv.cc Normal file
View file

@ -0,0 +1,169 @@
#include <iostream>
#include <cassert>
#include <cstring>
#include <memory>
#include "./string_view.hpp"
using string_view = jwt::basic_string_view<char>;
void basic_cons()
{
// Default construction
string_view sv{};
assert (sv.length() == 0 && "Size must be zero for default constructor");
// Construction from string literal
string_view sv2{"Arun Muralidharan"};
assert (sv2.length() == strlen("Arun Muralidharan") && "Lengths must match");
const char* haystack = "some really big data with infinite objects....";
// Construct using part of data
string_view sv3{haystack, 4};
assert (sv3.length() == 4 && "Partial construction is not ok");
assert (sv3.to_string() == "some" && "Partial strings are not equal");
return;
}
void iterator_test()
{
string_view sv{"Arun Muralidharan"};
for (auto c : sv) std::cout << c;
std::cout << std::endl;
return;
}
void str_operations()
{
string_view sv{"Arun Muralidharan"};
string_view tmp = sv;
sv.remove_prefix(5);
assert (sv.to_string() == "Muralidharan" && "Remove prefix failed");
sv = tmp;
sv.remove_suffix(strlen("Muralidharan"));
assert (sv.to_string() == "Arun " && "Remove suffix failed");
sv=tmp;
{
std::unique_ptr<char[]> dst{new char[32]};
sv.copy(dst.get(), 6, 0);
dst[6] = '\0';
assert (strlen(dst.get()) == 6 && "Copy Failed-1");
assert (std::string{dst.get()} == "Arun M" && "Copy Failed-2");
sv.copy(dst.get(), 8, 4);
dst[8] = '\0';
assert (strlen(dst.get()) == 8 && "Middle copy failed-1");
assert (std::string{dst.get()} == " Muralid" && "Middle copy failed-2");
}
{
auto ss1 = sv.substr(0, 4);
assert (ss1.to_string() == "Arun" && "Substr failed - 1");
auto ss2 = sv.substr(1, 3);
assert (ss2.to_string() == "run" && "Substr failed - 2");
auto ss3 = sv.substr(0);
assert (ss3.length() == sv.length() && "Substr failed - 3");
}
return;
}
void find_oper()
{
string_view sv{"Arun Muralidharan"};
auto pos = sv.find("Arun", 0, 4);
assert (pos == 0 && "Arun not found in sv");
pos = sv.find("arun", 0, 4);
assert (pos == string_view::npos && "arun is not there in sv");
sv = "This has a, in it.";
pos = sv.find_first_of(",", 0, 1);
assert (pos != string_view::npos);
assert (pos == 10 && "Comma not found at correct place");
pos = sv.find_first_of(",", 10, 1);
assert (pos != string_view::npos);
assert (pos == 10 && "Comma not found at correct place");
pos = sv.find_first_of(":", 10, 1);
assert (pos == string_view::npos);
pos = sv.find_last_of(",", 5, 1);
assert (pos == string_view::npos);
pos = sv.find_last_of(",", sv.length() - 1, 1);
assert (pos != string_view::npos);
assert (pos == 10 && "Comma not found at correct place");
pos = sv.find_first_of(".", 0, 1);
assert (pos == sv.length() - 1 && "Dot not found at correct place");
pos = sv.find_last_of(".", sv.length() - 2, 1);
assert (pos == string_view::npos);
pos = sv.find_last_of(".", sv.length() - 1, 1);
assert (pos == sv.length() - 1);
sv = "Some string :<> with some ??? pattern --**";
pos = sv.rfind("???", sv.length() - 1, 3);
assert (pos != string_view::npos && "??? not found");
assert (pos == 26 && "??? not found at the correct place");
sv = "ATCGTTCACGRRRTCGGGGACGTC";
pos = sv.find_first_not_of("ATCG");
assert (pos != string_view::npos);
assert (pos == 10);
return;
}
void conversions()
{
auto c2sv = [](int num) -> string_view {
switch (num) {
case 1: return "one";
case 2: return "two";
case 3: return "three";
default: return "many";
};
};
auto res = c2sv(2);
assert (res.to_string() == "two");
auto s2sv = [](std::string s) {
return s;
};
s2sv(static_cast<std::string>(res));
}
void comparisons()
{
string_view s1{"Apple"};
string_view s2{"Orange"};
assert (s1 != s2 && "Two string views are not equal");
assert (s2 > s1 && "Orange is lexicographically bigger than Apple");
s2 = "Apples";
assert (s2 > s1 && "Because Apples is plural");
}
int main() {
basic_cons();
iterator_test();
str_operations();
find_oper();
conversions();
comparisons();
return 0;
};