Unverified Commit 01c447af authored by Kip's avatar Kip Committed by GitHub

Merge pull request #932 from Tachi107/cpp17-std-string-view

Use std::string_view
parents 09a0c70a 27b3c93b
......@@ -33,7 +33,6 @@ install_headers([
'ssl_wrappers.h',
'stream.h',
'string_logger.h',
'string_view.h',
'tcp.h',
'timer_pool.h',
'transport.h',
......
......@@ -6,8 +6,6 @@
#pragma once
#include <pistache/view.h>
#include <cstring>
#include <limits>
#include <stdexcept>
......@@ -175,10 +173,9 @@ namespace Pistache
namespace helpers
{
inline Address httpAddr(const StringView& view)
inline Address httpAddr(const std::string_view& view)
{
auto const str = view.toString();
return Address(str);
return Address(std::string(view));
}
} // namespace helpers
......
......@@ -17,8 +17,6 @@
#include <pistache/http.h>
#include <pistache/http_defs.h>
#include "pistache/string_view.h"
namespace Pistache::Rest
{
......
#pragma once
#define CUSTOM_STRING_VIEW 1
#if __cplusplus >= 201703L
#if defined(__has_include)
#if __has_include(<string_view>)
#undef CUSTOM_STRING_VIEW
#include <string_view>
#elif __has_include(<experimental/string_view>)
#undef CUSTOM_STRING_VIEW
#include <experimental/string_view>
namespace std
{
using string_view = experimental::string_view;
}
#endif
#endif
#endif
#ifdef CUSTOM_STRING_VIEW
#include <endian.h>
#include <cstring>
#include <stdexcept>
#include <string>
namespace std
{
class string_view
{
public:
using size_type = std::size_t;
static constexpr size_type npos = size_type(-1);
constexpr string_view() noexcept
: data_(nullptr)
, size_(0)
{ }
constexpr string_view(const string_view& other) noexcept = default;
constexpr string_view(const char* s, size_type count)
: data_(s)
, size_(count)
{ }
explicit string_view(const char* s)
: data_(s)
, size_(strlen(s))
{ }
string_view substr(size_type pos, size_type count = npos) const
{
if (pos > size_)
{
throw std::out_of_range("Out of range.");
}
size_type rcount = std::min(count, size_ - pos);
return { data_ + pos, rcount };
}
constexpr size_type size() const noexcept { return size_; }
constexpr size_type length() const noexcept { return size_; }
constexpr char operator[](size_type pos) const { return data_[pos]; }
constexpr const char* data() const noexcept { return data_; }
bool operator==(const string_view& rhs) const
{
return (!std::lexicographical_compare(data_, data_ + size_, rhs.data_,
rhs.data_ + rhs.size_)
&& !std::lexicographical_compare(rhs.data_, rhs.data_ + rhs.size_,
data_, data_ + size_));
}
string_view& operator=(const string_view& view) noexcept = default;
size_type find(string_view v, size_type pos = 0) const noexcept
{
if (size_ < pos)
return npos;
if ((size_ - pos) < v.size_)
return npos;
for (; pos <= (size_ - v.size_); ++pos)
{
bool found = true;
for (size_type i = 0; i < v.size_; ++i)
{
if (data_[pos + i] != v.data_[i])
{
found = false;
break;
}
}
if (found)
{
return pos;
}
}
return npos;
}
size_type find(char ch, size_type pos = 0) const noexcept
{
return find(string_view(&ch, 1), pos);
}
size_type find(const char* s, size_type pos, size_type count) const
{
return find(string_view(s, count), pos);
}
size_type find(const char* s, size_type pos = 0) const
{
return find(string_view(s), pos);
}
size_type rfind(string_view v, size_type pos = npos) const noexcept
{
if (v.size_ > size_)
return npos;
if (pos > size_)
pos = size_;
size_t start = size_ - v.size_;
if (pos != npos)
start = pos;
for (size_t offset = 0; offset <= pos; ++offset, --start)
{
bool found = true;
for (size_t j = 0; j < v.size_; ++j)
{
if (data_[start + j] != v.data_[j])
{
found = false;
break;
}
}
if (found)
{
return start;
}
}
return npos;
}
size_type rfind(char c, size_type pos = npos) const noexcept
{
return rfind(string_view(&c, 1), pos);
}
size_type rfind(const char* s, size_type pos, size_type count) const
{
return rfind(string_view(s, count), pos);
}
size_type rfind(const char* s, size_type pos = npos) const
{
return rfind(string_view(s), pos);
}
constexpr bool empty() const noexcept { return size_ == 0; }
private:
const char* data_;
size_type size_;
};
template <>
struct hash<string_view>
{
//-----------------------------------------------------------------------------
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
private:
#ifdef __GNUC__
#define FORCE_INLINE __attribute__((always_inline)) inline
#else
#define FORCE_INLINE inline
#endif
static FORCE_INLINE std::uint32_t Rotl32(const std::uint32_t x,
const std::int8_t r)
{
return (x << r) | (x >> (32 - r));
}
static FORCE_INLINE std::uint32_t Getblock(const std::uint32_t* p,
const int i)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return p[i];
#else
std::uint32_t temp_number = p[i];
uint8_t(&number)[4] = *reinterpret_cast<uint8_t(*)[4]>(&temp_number);
std::swap(number[0], number[3]);
std::swap(number[1], number[2]);
return temp_number;
#endif
}
static FORCE_INLINE uint32_t fmix32(uint32_t h)
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
public:
string_view::size_type operator()(const string_view& str) const
{
const uint32_t len = static_cast<uint32_t>(str.length());
const uint8_t* data = reinterpret_cast<const uint8_t*>(str.data());
const int nblocks = static_cast<int>(len / 4);
uint32_t h1 = 0; // seed
const uint32_t c1 = 0xcc9e2d51U;
const uint32_t c2 = 0x1b873593U;
const uint32_t* blocks = reinterpret_cast<const uint32_t*>(data + nblocks * 4);
for (auto i = -nblocks; i; ++i)
{
uint32_t k1 = Getblock(blocks, i);
k1 *= c1;
k1 = Rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = Rotl32(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
const uint8_t* tail = data + nblocks * 4;
uint32_t k1 = 0;
switch (len & 3)
{
case 3:
k1 ^= tail[2] << 16;
/* fall through */
case 2:
k1 ^= tail[1] << 8;
/* fall through */
case 1:
k1 ^= tail[0];
k1 *= c1;
k1 = Rotl32(k1, 15);
k1 *= c2;
h1 ^= k1;
default:
break;
}
h1 ^= len;
h1 = fmix32(h1);
return hash<int>()(h1);
}
#undef FORCE_INLINE
};
} // namespace std
#endif
......@@ -32,7 +32,10 @@ namespace Pistache
namespace
{
std::pair<StringView, StringView> splitUrl(const std::string& url)
// Using const_cast can result in undefined behavior.
// C++17 provides a non-const .data() overload,
// but url must be passed as a non-const reference (or by value)
std::pair<std::string_view, std::string_view> splitUrl(const std::string& url)
{
RawStreamBuf<char> buf(const_cast<char*>(url.data()), url.size());
StreamCursor cursor(&buf);
......@@ -44,10 +47,10 @@ namespace Pistache
StreamCursor::Token hostToken(cursor);
match_until({ '?', '/' }, cursor);
StringView host(hostToken.rawText(), hostToken.size());
StringView page(cursor.offset(), buf.endptr());
std::string_view host(hostToken.rawText(), hostToken.size());
std::string_view page(cursor.offset(), buf.endptr() - buf.curptr());
return std::make_pair(std::move(host), std::move(page));
return std::make_pair(host, page);
}
} // namespace
......@@ -106,15 +109,12 @@ namespace Pistache
{
using Http::crlf;
auto res = request.resource();
auto s = splitUrl(res);
auto body = request.body();
auto query = request.query();
auto res = request.resource();
auto [host, path] = splitUrl(res);
auto body = request.body();
auto query = request.query();
auto host = s.first;
auto path = s.second;
auto pathStr = path.toString();
auto pathStr = std::string(path);
streamBuf << request.method() << " ";
if (pathStr[0] != '/')
......@@ -127,7 +127,7 @@ namespace Pistache
writeHeaders(streamBuf, request.headers());
writeHeader<Http::Header::UserAgent>(streamBuf, UA);
writeHeader<Http::Header::Host>(streamBuf, host.toString());
writeHeader<Http::Header::Host>(streamBuf, std::string(host));
if (!body.empty())
{
writeHeader<Http::Header::ContentLength>(streamBuf, body.size());
......@@ -1027,7 +1027,7 @@ namespace Pistache
auto resourceData = request.resource();
auto resource = splitUrl(resourceData);
auto conn = pool.pickConnection(resource.first);
auto conn = pool.pickConnection(std::string(resource.first));
if (conn == nullptr)
{
......@@ -1038,7 +1038,7 @@ namespace Pistache
auto data = std::make_shared<Connection::RequestData>(
std::move(resolve), std::move(reject), std::move(request), nullptr);
auto& queue = requestsQueues[resource.first];
auto& queue = requestsQueues[std::string(resource.first)];
if (!queue.enqueue(data))
data->reject(std::runtime_error("Queue is full"));
});
......
......@@ -36,7 +36,6 @@ pistache_test(listener_test)
pistache_test(request_size_test)
pistache_test(streaming_test)
pistache_test(rest_server_test)
pistache_test(string_view_test)
pistache_test(mailbox_test)
pistache_test(stream_test)
pistache_test(reactor_test)
......
......@@ -19,7 +19,6 @@ pistache_test_files = [
'request_size_test',
'streaming_test',
'rest_server_test',
'string_view_test',
'mailbox_test',
'stream_test',
'reactor_test',
......
#include "gtest/gtest.h"
#include <pistache/string_view.h>
#include <string>
TEST(string_view_test, substr_test)
{
std::string_view orig("test");
std::string_view targ("est");
std::string_view sub = orig.substr(1);
ASSERT_EQ(sub, targ);
sub = orig.substr(1, 10);
ASSERT_EQ(sub, targ);
ASSERT_THROW(orig.substr(6), std::out_of_range);
}
TEST(string_view_test, find_test)
{
std::string_view orig("test");
std::string_view find("est");
ASSERT_EQ(orig.find(find), std::size_t(1));
ASSERT_EQ(orig.find(find, 1), std::size_t(1));
ASSERT_EQ(orig.find(find, 2), std::size_t(-1));
ASSERT_EQ(orig.find('e'), std::size_t(1));
ASSERT_EQ(orig.find('e', 1), std::size_t(1));
ASSERT_EQ(orig.find('e', 2), std::size_t(-1));
ASSERT_EQ(orig.find('1'), std::size_t(-1));
ASSERT_EQ(orig.find("est"), std::size_t(1));
ASSERT_EQ(orig.find("est", 1), std::size_t(1));
ASSERT_EQ(orig.find("est", 1, 2), std::size_t(1));
ASSERT_EQ(orig.find("set"), std::size_t(-1));
ASSERT_EQ(orig.find("est", 2), std::size_t(-1));
ASSERT_EQ(orig.find("est", 2, 2), std::size_t(-1));
}
TEST(string_view_test, find_test_2)
{
std::string_view orig1("test");
std::string_view find1("est");
ASSERT_EQ(orig1.find(find1, std::size_t(-1)), std::size_t(-1));
ASSERT_EQ(orig1.find(find1, std::size_t(-1) - 2), std::size_t(-1));
std::string_view orig2("test");
std::string_view find2("");
ASSERT_EQ(orig2.find(find2, std::size_t(6)), std::size_t(-1));
ASSERT_EQ(orig2.find(find2, std::size_t(2)), std::size_t(2));
ASSERT_EQ(orig2.find(find2, std::size_t(-1)), std::size_t(-1));
std::string_view orig3("");
std::string_view find3("");
ASSERT_EQ(orig3.find(find3, std::size_t(0)), std::size_t(0));
ASSERT_EQ(orig3.find(find3, std::size_t(6)), std::size_t(-1));
}
TEST(string_view_test, rfind_test)
{
std::string_view orig("test");
std::string_view find("est");
ASSERT_EQ(orig.rfind(find), std::size_t(1));
ASSERT_EQ(orig.rfind(find, 1), std::size_t(1));
ASSERT_EQ(orig.rfind('e'), std::size_t(1));
ASSERT_EQ(orig.rfind('e', 1), std::size_t(1));
ASSERT_EQ(orig.rfind('q'), std::size_t(-1));
ASSERT_EQ(orig.rfind("est"), std::size_t(1));
ASSERT_EQ(orig.rfind("est", 1), std::size_t(1));
ASSERT_EQ(orig.rfind("est", 1, 2), std::size_t(1));
ASSERT_EQ(orig.rfind("set"), std::size_t(-1));
}
TEST(string_view_test, rfind_test_2)
{
std::string_view orig1("e");
std::string_view find1("e");
ASSERT_EQ(orig1.rfind(find1), std::size_t(0));
ASSERT_EQ(orig1.rfind(find1, 1), std::size_t(0));
std::string_view orig2("e");
std::string_view find2("");
ASSERT_EQ(orig2.rfind(find2), std::size_t(1));
ASSERT_EQ(orig2.rfind(find2, 1), std::size_t(1));
std::string_view orig3("");
std::string_view find3("e");
ASSERT_EQ(orig3.rfind(find3), std::size_t(-1));
ASSERT_EQ(orig3.rfind(find3, 1), std::size_t(-1));
std::string_view orig4("");
std::string_view find4("");
ASSERT_EQ(orig4.rfind(find4), std::size_t(0));
ASSERT_EQ(orig4.rfind(find4, 1), std::size_t(0));
std::string_view orig5("a");
std::string_view find5("b");
ASSERT_EQ(orig5.rfind(find5), std::size_t(-1));
ASSERT_EQ(orig5.rfind(find5, 4), std::size_t(-1));
}
TEST(string_view_test, emptiness)
{
std::string_view e1;
std::string_view e2("");
std::string_view e3("test", 0);
std::string_view ne("test");
ASSERT_TRUE(e1.empty());
ASSERT_TRUE(e2.empty());
ASSERT_TRUE(e3.empty());
ASSERT_FALSE(ne.empty());
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment