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):
|
||||
m_views {
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
},
|
||||
m_offsets {},
|
||||
m_value (std::move (_value))
|
||||
{
|
||||
minimal_percent_encode (m_value);
|
||||
|
||||
parse ();
|
||||
|
||||
if (m_views[0].begin () == nullptr)
|
||||
m_views[0] = { m_value.data (), 0 };
|
||||
|
||||
for (int i = 1; i < NUM_COMPONENTS; ++i) {
|
||||
if (m_views[i].data () != nullptr)
|
||||
if (m_offsets[i].second != m_offsets[i].first)
|
||||
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);
|
||||
@ -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
|
||||
combine_components (
|
||||
@ -155,9 +122,12 @@ std::string_view
|
||||
uri::heirarchical (void) const&
|
||||
{
|
||||
for (int i = USER; i <= PATH; ++i)
|
||||
if (!m_views[i].empty ())
|
||||
return { m_views[i].data (), std::size_t (m_views[PATH].end () - m_views[i].data ()) };
|
||||
return { m_views[USER].data (), 0 };
|
||||
if (m_offsets[i].first != m_offsets[i].second)
|
||||
return {
|
||||
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&
|
||||
{
|
||||
for (int i = USER; i <= PORT; ++i)
|
||||
if (!m_views[i].empty ())
|
||||
return { m_views[i].data (), std::size_t (m_views[PORT ].end () - m_views[i].data ()) };
|
||||
return { m_views[USER].data (), 0 };
|
||||
if (m_offsets[i].first != m_offsets[i].second)
|
||||
return {
|
||||
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&
|
||||
{
|
||||
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
|
||||
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_views[c].data () - m_value.data (),
|
||||
m_views[c].size (),
|
||||
m_offsets[c].first,
|
||||
m_offsets[c].second - m_offsets[c].first,
|
||||
val
|
||||
);
|
||||
auto const offset = m_value.data () - base;
|
||||
|
||||
for (int i = 0; i <= c; ++i)
|
||||
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)
|
||||
m_views[i] += offset + diff;
|
||||
m_offsets[c].second = m_offsets[c].first + val.size ();
|
||||
|
||||
for (int i = c + 1; i != component::NUM_COMPONENTS; ++i) {
|
||||
m_offsets[i].first += diff;
|
||||
m_offsets[i].second += diff;
|
||||
}
|
||||
|
||||
CHECK_SANITY (*this);
|
||||
}
|
||||
@ -208,19 +186,19 @@ uri::set (component c, std::string_view val)
|
||||
//-----------------------------------------------------------------------------
|
||||
void uri::clear_fragment ()
|
||||
{
|
||||
if (!m_views[FRAGMENT])
|
||||
if (m_offsets[FRAGMENT].first == m_offsets[FRAGMENT].second)
|
||||
return;
|
||||
|
||||
m_value.erase (
|
||||
m_views[FRAGMENT].begin () - m_value.data (),
|
||||
m_views[FRAGMENT].size ()
|
||||
m_offsets[FRAGMENT].first,
|
||||
m_offsets[FRAGMENT].second - m_offsets[FRAGMENT].first
|
||||
);
|
||||
CHECK (m_value.back () == '#');
|
||||
m_value.pop_back ();
|
||||
|
||||
// Don't set this to nullptr. Other code assumes these views aren't null
|
||||
// (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
|
||||
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 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_end { ; }
|
||||
|
||||
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_end { CHECK (starts[HOST]); m_views[HOST] = { starts[HOST], p }; }
|
||||
action host_end { record_component (HOST); }
|
||||
|
||||
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_end { ; }
|
||||
|
||||
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_end { CHECK (starts[QUERY]); m_views[QUERY] = { starts[QUERY], p }; }
|
||||
action query_end { record_component (QUERY); }
|
||||
|
||||
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_end {}
|
||||
@ -79,20 +79,22 @@ cruft::uri::parse (void)
|
||||
{
|
||||
char const *starts[NUM_COMPONENTS] = {};
|
||||
|
||||
m_views = {
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
const char *str = m_value.data ();
|
||||
const char *p = m_value.data ();
|
||||
const char *pe = m_value.data () + m_value.size ();
|
||||
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;
|
||||
|
||||
int cs;
|
||||
@ -100,6 +102,17 @@ cruft::uri::parse (void)
|
||||
%%write init;
|
||||
%%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)
|
||||
throw parse_error (fmt::format ("invalid uri '{}'", m_value));
|
||||
}
|
21
uri.hpp
21
uri.hpp
@ -35,10 +35,12 @@ namespace cruft {
|
||||
class uri {
|
||||
public:
|
||||
explicit uri (std::string &&);
|
||||
uri& operator= (uri &&) noexcept;
|
||||
|
||||
uri (uri const&);
|
||||
uri& operator= (uri const&);
|
||||
uri (uri &&) noexcept = default;
|
||||
uri& operator= (uri &&) noexcept = default;
|
||||
|
||||
uri (uri const&) = default;
|
||||
uri& operator= (uri const&) = default;
|
||||
|
||||
explicit uri (const std::string&);
|
||||
explicit uri (const char *);
|
||||
@ -100,16 +102,16 @@ namespace cruft {
|
||||
std::string_view pq (void) const&
|
||||
{
|
||||
return {
|
||||
m_views[PATH].begin (),
|
||||
m_views[QUERY].end ()
|
||||
m_value.data () + m_offsets[PATH].first,
|
||||
m_value.data () + m_offsets[QUERY].second
|
||||
};
|
||||
}
|
||||
|
||||
std::string_view
|
||||
pqf (void) const& {
|
||||
return {
|
||||
m_views[PATH].begin (),
|
||||
m_views[FRAGMENT].end ()
|
||||
m_value.data () + m_offsets[PATH].first,
|
||||
m_value.data () + m_offsets[FRAGMENT].second
|
||||
};
|
||||
}
|
||||
|
||||
@ -118,14 +120,15 @@ namespace cruft {
|
||||
// void clear (component);
|
||||
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*>);
|
||||
|
||||
private:
|
||||
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;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user