Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
uritemplate_router.h
1#ifndef SOURCEMETA_CORE_URITEMPLATE_ROUTER_H_
2#define SOURCEMETA_CORE_URITEMPLATE_ROUTER_H_
3
4#ifndef SOURCEMETA_CORE_URITEMPLATE_EXPORT
5#include <sourcemeta/core/uritemplate_export.h>
6#endif
7
8#include <sourcemeta/core/io.h>
9
10#include <cstddef> // std::size_t
11#include <cstdint> // std::uint16_t, std::uint32_t, std::uint8_t, std::int64_t
12#include <filesystem> // std::filesystem::path
13#include <functional> // std::function
14#include <memory> // std::unique_ptr
15#include <span> // std::span
16#include <string> // std::string
17#include <string_view> // std::string_view
18#include <tuple> // std::tuple
19#include <unordered_map> // std::unordered_map
20#include <utility> // std::pair
21#include <variant> // std::variant
22#include <vector> // std::vector
23
24namespace sourcemeta::core {
25
26#if defined(_MSC_VER)
27#pragma warning(push)
28#pragma warning(disable : 4251)
29#endif
30
45class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouter {
46 friend class URITemplateRouterView;
47
48public:
50 using Identifier = std::uint16_t;
51
53 using Index = std::uint8_t;
54
56 using Callback =
57 std::function<void(Index, std::string_view, std::string_view)>;
58
60 using ArgumentValue = std::variant<std::string_view, std::int64_t, bool>;
61
63 using Argument = std::pair<std::string_view, ArgumentValue>;
64
67 std::function<void(std::string_view, const ArgumentValue &)>;
68
70 enum class NodeType : std::uint8_t {
72 Root = 0,
74 Literal = 1,
76 Variable = 2,
78 Expansion = 3,
80 OptionalExpansion = 4
81 };
82
84 struct Node {
92 std::string_view value;
93
94 // This children distinction enforces that there can only be one non-literal
95 // child at the type level. Also allows us to more efficiently search on
96 // literals
98 std::vector<std::unique_ptr<Node>> literals;
100 std::unique_ptr<Node> variable;
101 };
102
104 URITemplateRouter() = default;
105
110 explicit URITemplateRouter(std::string_view base_path,
111 std::string_view base_url = {});
112
113 // To avoid mistakes
114 URITemplateRouter(const URITemplateRouter &) = delete;
116 auto operator=(const URITemplateRouter &) -> URITemplateRouter & = delete;
117 auto operator=(URITemplateRouter &&) -> URITemplateRouter & = delete;
118
123 auto add(const std::string_view uri_template,
124 const std::string_view operation_id, const Identifier identifier,
125 const Identifier context = 0,
126 const std::span<const Argument> arguments = {}) -> void;
127
131 const std::span<const Argument> arguments = {}) -> void;
132
135 [[nodiscard]] auto match(const std::string_view path,
136 const Callback &callback) const
137 -> std::pair<Identifier, Identifier>;
138
146 [[nodiscard]] auto
147 describes(const std::string_view path,
148 const std::string_view base_path = {}) const noexcept -> bool;
149
151 [[nodiscard]] auto root() const noexcept -> const Node &;
152
154 auto arguments(const Identifier identifier,
155 const ArgumentCallback &callback) const -> void;
156
158 [[nodiscard]] auto arguments() const noexcept
159 -> const std::vector<std::pair<Identifier, std::vector<Argument>>> &;
160
162 [[nodiscard]] auto base_path() const noexcept -> std::string_view;
163
165 [[nodiscard]] auto base_url() const noexcept -> std::string_view;
166
168 [[nodiscard]] auto size() const noexcept -> std::size_t;
169
171 [[nodiscard]] auto at(const std::size_t index) const -> Identifier;
172
175 [[nodiscard]] auto context(const Identifier identifier) const -> Identifier;
176
179 [[nodiscard]] auto path(const Identifier identifier) const -> std::string;
180
184 [[nodiscard]] auto operation(const std::string_view operation_id) const
185 -> std::pair<Identifier, Identifier>;
186
189 [[nodiscard]] auto operation_id(const Identifier identifier) const
190 -> std::string_view;
191
192private:
193 Node root_;
194 Node otherwise_;
195 std::string base_path_;
196 std::string base_url_;
197 std::vector<std::pair<Identifier, std::vector<Argument>>> arguments_;
198 std::vector<std::tuple<Identifier, Identifier, std::string_view>> entries_;
199 std::unordered_map<std::string_view, std::pair<Identifier, Identifier>>
200 operations_;
201};
202
205class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouterView {
206public:
208 static auto save(const URITemplateRouter &router,
209 const std::filesystem::path &path) -> void;
210
212 URITemplateRouterView(const std::filesystem::path &path);
213
216 URITemplateRouterView(const std::uint8_t *data, std::size_t size);
217
219
220 // To avoid mistakes
223 auto operator=(const URITemplateRouterView &)
224 -> URITemplateRouterView & = delete;
225 auto operator=(URITemplateRouterView &&) -> URITemplateRouterView & = delete;
226
229 [[nodiscard]] auto match(const std::string_view path,
230 const URITemplateRouter::Callback &callback) const
233
241 [[nodiscard]] auto
242 describes(const std::string_view path,
243 const std::string_view base_path = {}) const noexcept -> bool;
244
247 const URITemplateRouter::ArgumentCallback &callback) const
248 -> void;
249
251 [[nodiscard]] auto base_path() const noexcept -> std::string_view;
252
254 [[nodiscard]] auto base_url() const noexcept -> std::string_view;
255
257 [[nodiscard]] auto size() const noexcept -> std::size_t;
258
262 [[nodiscard]] auto operation(const std::string_view operation_id) const
263 -> std::pair<URITemplateRouter::Identifier,
264 URITemplateRouter::Identifier>;
265
267 [[nodiscard]] auto at(const std::size_t index) const
268 -> URITemplateRouter::Identifier;
269
272 [[nodiscard]] auto
273 context(const URITemplateRouter::Identifier identifier) const
274 -> URITemplateRouter::Identifier;
275
278 [[nodiscard]] auto path(const URITemplateRouter::Identifier identifier) const
279 -> std::string;
280
283 [[nodiscard]] auto
284 operation_id(const URITemplateRouter::Identifier identifier) const
285 -> std::string_view;
286
287private:
288 const std::uint8_t *data_{nullptr};
289 std::size_t size_{0};
290 std::unique_ptr<FileView> owner_;
291 // Holds an eight-byte-aligned copy of an unaligned external buffer, so the
292 // over-aligned serialized nodes are always read from aligned storage
293 std::vector<std::uint64_t> owned_;
294};
295
296#if defined(_MSC_VER)
297#pragma warning(pop)
298#endif
299
300} // namespace sourcemeta::core
301
302#endif
URITemplateRouter()=default
Construct an empty router.
auto at(const std::size_t index) const -> URITemplateRouter::Identifier
Get the identifier of the route at the given positional index.
std::function< void(std::string_view, const ArgumentValue &)> ArgumentCallback
The argument callback (name, value).
Definition uritemplate_router.h:66
URITemplateRouterView(const std::filesystem::path &path)
Construct a view by loading a serialized router from a file.
URITemplateRouterView(const std::uint8_t *data, std::size_t size)
auto base_path() const noexcept -> std::string_view
Access the base path prefix.
URITemplateRouter(std::string_view base_path, std::string_view base_url={})
std::function< void(Index, std::string_view, std::string_view)> Callback
The match callback (index, name, value).
Definition uritemplate_router.h:56
auto context(const Identifier identifier) const -> Identifier
auto describes(const std::string_view path, const std::string_view base_path={}) const noexcept -> bool
auto base_url() const noexcept -> std::string_view
Access the base URL associated with the router.
auto path(const Identifier identifier) const -> std::string
auto path(const URITemplateRouter::Identifier identifier) const -> std::string
auto describes(const std::string_view path, const std::string_view base_path={}) const noexcept -> bool
auto operation_id(const Identifier identifier) const -> std::string_view
auto match(const std::string_view path, const URITemplateRouter::Callback &callback) const -> std::pair< URITemplateRouter::Identifier, URITemplateRouter::Identifier >
auto operation(const std::string_view operation_id) const -> std::pair< Identifier, Identifier >
auto context(const URITemplateRouter::Identifier identifier) const -> URITemplateRouter::Identifier
auto arguments(const Identifier identifier, const ArgumentCallback &callback) const -> void
Access the stored arguments for a given route identifier.
auto base_url() const noexcept -> std::string_view
Access the base URL associated with the router.
auto root() const noexcept -> const Node &
Access the root node of the trie.
auto match(const std::string_view path, const Callback &callback) const -> std::pair< Identifier, Identifier >
auto size() const noexcept -> std::size_t
Get the number of registered routes.
auto operation_id(const URITemplateRouter::Identifier identifier) const -> std::string_view
static auto save(const URITemplateRouter &router, const std::filesystem::path &path) -> void
Save a router to a binary file.
auto operation(const std::string_view operation_id) const -> std::pair< URITemplateRouter::Identifier, URITemplateRouter::Identifier >
std::variant< std::string_view, std::int64_t, bool > ArgumentValue
The value of a route argument.
Definition uritemplate_router.h:60
auto at(const std::size_t index) const -> Identifier
Get the identifier of the route at the given positional index.
auto base_path() const noexcept -> std::string_view
Access the base path prefix.
std::uint16_t Identifier
A handler identifier 0 means "no handler".
Definition uritemplate_router.h:50
std::uint8_t Index
The variable index type.
Definition uritemplate_router.h:53
std::pair< std::string_view, ArgumentValue > Argument
A named route argument.
Definition uritemplate_router.h:63
auto add(const std::string_view uri_template, const std::string_view operation_id, const Identifier identifier, const Identifier context=0, const std::span< const Argument > arguments={}) -> void
NodeType
The type of a node in the router trie.
Definition uritemplate_router.h:70
@ Root
The root of the trie.
Definition uritemplate_router.h:72
auto size() const noexcept -> std::size_t
Get the number of registered routes.
auto otherwise(const Identifier context, const std::span< const Argument > arguments={}) -> void
auto arguments(const URITemplateRouter::Identifier identifier, const URITemplateRouter::ArgumentCallback &callback) const -> void
Access the stored arguments for a given route identifier.
Definition uritemplate_router.h:45
A node in the router trie.
Definition uritemplate_router.h:84
std::string_view value
The literal text or variable name of this node.
Definition uritemplate_router.h:92
Identifier context
The context identifier associated with this node.
Definition uritemplate_router.h:88
std::vector< std::unique_ptr< Node > > literals
The literal children of this node.
Definition uritemplate_router.h:98
Identifier identifier
The handler identifier of the route ending at this node.
Definition uritemplate_router.h:86
NodeType type
The kind of component this node represents.
Definition uritemplate_router.h:90
std::unique_ptr< Node > variable
The single non-literal child of this node.
Definition uritemplate_router.h:100