uri: store offsets rather than pointers
This simplifies copy and assignment.
This commit is contained in:
parent
2d18241e61
commit
dc46dc7c91
110
uri.cpp
110
uri.cpp
@ -24,28 +24,20 @@ minimal_percent_encode (std::string &str)
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
cruft::uri::uri (std::string &&_value):
|
cruft::uri::uri (std::string &&_value):
|
||||||
m_views {
|
m_offsets {},
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
},
|
|
||||||
m_value (std::move (_value))
|
m_value (std::move (_value))
|
||||||
{
|
{
|
||||||
minimal_percent_encode (m_value);
|
minimal_percent_encode (m_value);
|
||||||
|
|
||||||
parse ();
|
parse ();
|
||||||
|
|
||||||
if (m_views[0].begin () == nullptr)
|
|
||||||
m_views[0] = { m_value.data (), 0 };
|
|
||||||
|
|
||||||
for (int i = 1; i < NUM_COMPONENTS; ++i) {
|
for (int i = 1; i < NUM_COMPONENTS; ++i) {
|
||||||
if (m_views[i].data () != nullptr)
|
if (m_offsets[i].second != m_offsets[i].first)
|
||||||
continue;
|
continue;
|
||||||
m_views[i] = { m_views[i - 1].end (), 0 };
|
m_offsets[i] = {
|
||||||
|
m_offsets[i - 1].second,
|
||||||
|
m_offsets[i - 1].second
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_SANITY (*this);
|
CHECK_SANITY (*this);
|
||||||
@ -70,31 +62,6 @@ uri::uri (const std::string &_value):
|
|||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
uri::uri (uri const &rhs)
|
|
||||||
: m_views (rhs.m_views)
|
|
||||||
, m_value (rhs.m_value)
|
|
||||||
{
|
|
||||||
auto const offset = rhs.m_value.data () - m_value.data ();
|
|
||||||
|
|
||||||
for (auto &i: m_views)
|
|
||||||
i -= offset;
|
|
||||||
|
|
||||||
CHECK_SANITY (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
uri& uri::operator= (uri &&rhs) noexcept
|
|
||||||
{
|
|
||||||
m_views = std::move (rhs.m_views);
|
|
||||||
m_value = std::move (rhs.m_value);
|
|
||||||
|
|
||||||
CHECK_SANITY (*this);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
static std::string
|
static std::string
|
||||||
combine_components (
|
combine_components (
|
||||||
@ -155,9 +122,12 @@ std::string_view
|
|||||||
uri::heirarchical (void) const&
|
uri::heirarchical (void) const&
|
||||||
{
|
{
|
||||||
for (int i = USER; i <= PATH; ++i)
|
for (int i = USER; i <= PATH; ++i)
|
||||||
if (!m_views[i].empty ())
|
if (m_offsets[i].first != m_offsets[i].second)
|
||||||
return { m_views[i].data (), std::size_t (m_views[PATH].end () - m_views[i].data ()) };
|
return {
|
||||||
return { m_views[USER].data (), 0 };
|
m_value.data () + m_offsets[ i].first,
|
||||||
|
m_value.data () + m_offsets[PATH].second
|
||||||
|
};
|
||||||
|
return { m_value.data () + m_offsets[USER].first, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,9 +136,15 @@ std::string_view
|
|||||||
uri::authority (void) const&
|
uri::authority (void) const&
|
||||||
{
|
{
|
||||||
for (int i = USER; i <= PORT; ++i)
|
for (int i = USER; i <= PORT; ++i)
|
||||||
if (!m_views[i].empty ())
|
if (m_offsets[i].first != m_offsets[i].second)
|
||||||
return { m_views[i].data (), std::size_t (m_views[PORT ].end () - m_views[i].data ()) };
|
return {
|
||||||
return { m_views[USER].data (), 0 };
|
m_value.data () + m_offsets[ i].first,
|
||||||
|
m_value.data () + m_offsets[PORT].second
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
m_value.data () + m_offsets[USER].first, 0
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -177,7 +153,10 @@ std::string_view
|
|||||||
uri::get (component c) const&
|
uri::get (component c) const&
|
||||||
{
|
{
|
||||||
CHECK_INDEX (c, NUM_COMPONENTS);
|
CHECK_INDEX (c, NUM_COMPONENTS);
|
||||||
return { m_views[c].data (), m_views[c].size () };
|
return {
|
||||||
|
m_value.data () + m_offsets[c].first,
|
||||||
|
m_value.data () + m_offsets[c].second,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -185,21 +164,20 @@ uri::get (component c) const&
|
|||||||
void
|
void
|
||||||
uri::set (component c, std::string_view val)
|
uri::set (component c, std::string_view val)
|
||||||
{
|
{
|
||||||
std::ptrdiff_t const diff = val.size () - m_views[c].size ();
|
std::ptrdiff_t const diff = val.size () - (m_offsets[c].second - m_offsets[c].first);
|
||||||
|
|
||||||
auto const base = m_value.data ();
|
|
||||||
m_value.replace (
|
m_value.replace (
|
||||||
m_views[c].data () - m_value.data (),
|
m_offsets[c].first,
|
||||||
m_views[c].size (),
|
m_offsets[c].second - m_offsets[c].first,
|
||||||
val
|
val
|
||||||
);
|
);
|
||||||
auto const offset = m_value.data () - base;
|
|
||||||
|
|
||||||
for (int i = 0; i <= c; ++i)
|
m_offsets[c].second = m_offsets[c].first + val.size ();
|
||||||
m_views[i] += offset;
|
|
||||||
m_views[c] = { m_views[c].begin (), m_views[c].end () + diff };
|
for (int i = c + 1; i != component::NUM_COMPONENTS; ++i) {
|
||||||
for (int i = c + 1; i != component::NUM_COMPONENTS; ++i)
|
m_offsets[i].first += diff;
|
||||||
m_views[i] += offset + diff;
|
m_offsets[i].second += diff;
|
||||||
|
}
|
||||||
|
|
||||||
CHECK_SANITY (*this);
|
CHECK_SANITY (*this);
|
||||||
}
|
}
|
||||||
@ -208,19 +186,19 @@ uri::set (component c, std::string_view val)
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void uri::clear_fragment ()
|
void uri::clear_fragment ()
|
||||||
{
|
{
|
||||||
if (!m_views[FRAGMENT])
|
if (m_offsets[FRAGMENT].first == m_offsets[FRAGMENT].second)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_value.erase (
|
m_value.erase (
|
||||||
m_views[FRAGMENT].begin () - m_value.data (),
|
m_offsets[FRAGMENT].first,
|
||||||
m_views[FRAGMENT].size ()
|
m_offsets[FRAGMENT].second - m_offsets[FRAGMENT].first
|
||||||
);
|
);
|
||||||
CHECK (m_value.back () == '#');
|
CHECK (m_value.back () == '#');
|
||||||
m_value.pop_back ();
|
m_value.pop_back ();
|
||||||
|
|
||||||
// Don't set this to nullptr. Other code assumes these views aren't null
|
// Don't set this to nullptr. Other code assumes these views aren't null
|
||||||
// (eg, for offsetting during copy construction).
|
// (eg, for offsetting during copy construction).
|
||||||
m_views[FRAGMENT] = { m_views[FRAGMENT - 1].end (), 0 };
|
m_offsets[FRAGMENT].first = m_offsets[FRAGMENT].second = m_offsets[FRAGMENT - 1].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -267,6 +245,18 @@ cruft::vector_to_query (std::vector<std::pair<std::string, std::string>> const &
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::array<std::string_view, cruft::uri::NUM_COMPONENTS>
|
||||||
|
uri::components () const& noexcept
|
||||||
|
{
|
||||||
|
std::array<std::string_view, cruft::uri::NUM_COMPONENTS> res;
|
||||||
|
for (int i = 0; i != NUM_COMPONENTS; ++i)
|
||||||
|
res[i] = get (uri::component (i));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
bool
|
bool
|
||||||
cruft::operator== (cruft::uri const &a, cruft::uri const &b) noexcept
|
cruft::operator== (cruft::uri const &a, cruft::uri const &b) noexcept
|
||||||
|
47
uri.cpp.rl
47
uri.cpp.rl
@ -29,31 +29,31 @@ using cruft::uri;
|
|||||||
action failure {__success = false; }
|
action failure {__success = false; }
|
||||||
|
|
||||||
action scheme_begin { starts[SCHEME] = p; }
|
action scheme_begin { starts[SCHEME] = p; }
|
||||||
action scheme_end { CHECK (starts[SCHEME]); m_views[SCHEME] = { starts[SCHEME], p }; }
|
action scheme_end { record_component (SCHEME); }
|
||||||
|
|
||||||
action hier_begin { ; }
|
action hier_begin { ; }
|
||||||
action hier_end { ; }
|
action hier_end { ; }
|
||||||
|
|
||||||
action user_begin { starts[USER] = p; }
|
action user_begin { starts[USER] = p; }
|
||||||
action user_end { CHECK (starts[USER]); m_views[USER] = { starts[USER], p }; }
|
action user_end { record_component (USER); }
|
||||||
|
|
||||||
action host_begin { starts[HOST] = p; }
|
action host_begin { starts[HOST] = p; }
|
||||||
action host_end { CHECK (starts[HOST]); m_views[HOST] = { starts[HOST], p }; }
|
action host_end { record_component (HOST); }
|
||||||
|
|
||||||
action port_begin { starts[PORT] = p; }
|
action port_begin { starts[PORT] = p; }
|
||||||
action port_end { CHECK (starts[PORT]); m_views[PORT] = { starts[PORT], p }; }
|
action port_end { record_component (PORT); }
|
||||||
|
|
||||||
action authority_begin { ; }
|
action authority_begin { ; }
|
||||||
action authority_end { ; }
|
action authority_end { ; }
|
||||||
|
|
||||||
action path_begin { starts[PATH] = p; }
|
action path_begin { starts[PATH] = p; }
|
||||||
action path_end { CHECK (starts[PATH]); m_views[PATH] = { starts[PATH], p }; }
|
action path_end { record_component (PATH); }
|
||||||
|
|
||||||
action query_begin { starts[QUERY] = p; }
|
action query_begin { starts[QUERY] = p; }
|
||||||
action query_end { CHECK (starts[QUERY]); m_views[QUERY] = { starts[QUERY], p }; }
|
action query_end { record_component (QUERY); }
|
||||||
|
|
||||||
action fragment_begin { starts[FRAGMENT] = p; }
|
action fragment_begin { starts[FRAGMENT] = p; }
|
||||||
action fragment_end { CHECK (starts[FRAGMENT]); m_views[FRAGMENT] = { starts[FRAGMENT], p }; }
|
action fragment_end { record_component (FRAGMENT); }
|
||||||
|
|
||||||
action uri_begin {}
|
action uri_begin {}
|
||||||
action uri_end {}
|
action uri_end {}
|
||||||
@ -79,20 +79,22 @@ cruft::uri::parse (void)
|
|||||||
{
|
{
|
||||||
char const *starts[NUM_COMPONENTS] = {};
|
char const *starts[NUM_COMPONENTS] = {};
|
||||||
|
|
||||||
m_views = {
|
const char *str = m_value.data ();
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *p = m_value.data ();
|
const char *p = m_value.data ();
|
||||||
const char *pe = m_value.data () + m_value.size ();
|
const char *pe = m_value.data () + m_value.size ();
|
||||||
const char *eof = pe;
|
const char *eof = pe;
|
||||||
|
|
||||||
|
m_offsets = {};
|
||||||
|
auto record_component = [&] (int const idx) {
|
||||||
|
// CHECK (m_offsets[idx].first == 0);
|
||||||
|
// CHECK (m_offsets[idx].second == 0);
|
||||||
|
|
||||||
|
CHECK (starts[idx]);
|
||||||
|
|
||||||
|
m_offsets[idx].first = starts[idx] - str;
|
||||||
|
m_offsets[idx].second = p - str;
|
||||||
|
};
|
||||||
|
|
||||||
bool __success = false;
|
bool __success = false;
|
||||||
|
|
||||||
int cs;
|
int cs;
|
||||||
@ -100,6 +102,17 @@ cruft::uri::parse (void)
|
|||||||
%%write init;
|
%%write init;
|
||||||
%%write exec;
|
%%write exec;
|
||||||
|
|
||||||
|
if constexpr (debug_enabled) {
|
||||||
|
if (!m_value.empty ())
|
||||||
|
CHECK (std::any_of (
|
||||||
|
m_offsets.begin (),
|
||||||
|
m_offsets.end (),
|
||||||
|
[] (auto const &i)
|
||||||
|
{
|
||||||
|
return !!i.second;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (!__success)
|
if (!__success)
|
||||||
throw parse_error (fmt::format ("invalid uri '{}'", m_value));
|
throw parse_error (fmt::format ("invalid uri '{}'", m_value));
|
||||||
}
|
}
|
21
uri.hpp
21
uri.hpp
@ -35,10 +35,12 @@ namespace cruft {
|
|||||||
class uri {
|
class uri {
|
||||||
public:
|
public:
|
||||||
explicit uri (std::string &&);
|
explicit uri (std::string &&);
|
||||||
uri& operator= (uri &&) noexcept;
|
|
||||||
|
|
||||||
uri (uri const&);
|
uri (uri &&) noexcept = default;
|
||||||
uri& operator= (uri const&);
|
uri& operator= (uri &&) noexcept = default;
|
||||||
|
|
||||||
|
uri (uri const&) = default;
|
||||||
|
uri& operator= (uri const&) = default;
|
||||||
|
|
||||||
explicit uri (const std::string&);
|
explicit uri (const std::string&);
|
||||||
explicit uri (const char *);
|
explicit uri (const char *);
|
||||||
@ -100,16 +102,16 @@ namespace cruft {
|
|||||||
std::string_view pq (void) const&
|
std::string_view pq (void) const&
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
m_views[PATH].begin (),
|
m_value.data () + m_offsets[PATH].first,
|
||||||
m_views[QUERY].end ()
|
m_value.data () + m_offsets[QUERY].second
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view
|
std::string_view
|
||||||
pqf (void) const& {
|
pqf (void) const& {
|
||||||
return {
|
return {
|
||||||
m_views[PATH].begin (),
|
m_value.data () + m_offsets[PATH].first,
|
||||||
m_views[FRAGMENT].end ()
|
m_value.data () + m_offsets[FRAGMENT].second
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,14 +120,15 @@ namespace cruft {
|
|||||||
// void clear (component);
|
// void clear (component);
|
||||||
void clear_fragment (void);
|
void clear_fragment (void);
|
||||||
|
|
||||||
auto components (void) const& noexcept { return m_views; }
|
std::array<std::string_view, NUM_COMPONENTS>
|
||||||
|
components (void) const& noexcept;
|
||||||
|
|
||||||
static std::string percent_decode (view<const char*>);
|
static std::string percent_decode (view<const char*>);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parse (void);
|
void parse (void);
|
||||||
|
|
||||||
std::array<view<const char*>, NUM_COMPONENTS> m_views;
|
std::array<std::pair<int, int>, NUM_COMPONENTS> m_offsets;
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user