diff --git a/uri.cpp b/uri.cpp index 56c669ec..ea1a3ee3 100644 --- a/uri.cpp +++ b/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> const & } +/////////////////////////////////////////////////////////////////////////////// +std::array +uri::components () const& noexcept +{ + std::array 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 diff --git a/uri.cpp.rl b/uri.cpp.rl index 7da6620c..157e95d8 100644 --- a/uri.cpp.rl +++ b/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)); } \ No newline at end of file diff --git a/uri.hpp b/uri.hpp index 4fa9bc5d..6a0701b1 100644 --- a/uri.hpp +++ b/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 + components (void) const& noexcept; static std::string percent_decode (view); private: void parse (void); - std::array, NUM_COMPONENTS> m_views; + std::array, NUM_COMPONENTS> m_offsets; std::string m_value; };