mirror of
https://github.com/CrowCpp/Crow.git
synced 2024-06-07 21:10:44 +00:00
Merge pull request #65 from mrozigor/moredocs
documented as much as possible relating to the API reference
This commit is contained in:
commit
dce8e63646
@ -4,6 +4,7 @@ Crow is a C++ microframework for web. (inspired by Python Flask)
|
|||||||
|
|
||||||
[![Build Status](https://travis-ci.com/mrozigor/crow.svg?branch=master)](https://travis-ci.com/mrozigor/crow)
|
[![Build Status](https://travis-ci.com/mrozigor/crow.svg?branch=master)](https://travis-ci.com/mrozigor/crow)
|
||||||
[![Coverage Status](https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master)](https://coveralls.io/github/mrozigor/crow?branch=master)
|
[![Coverage Status](https://coveralls.io/repos/github/mrozigor/crow/badge.svg?branch=master)](https://coveralls.io/github/mrozigor/crow?branch=master)
|
||||||
|
[![Documentation](https://img.shields.io/badge/-Documentation-informational)](https://mrozigor.github.io/crow)
|
||||||
[![Gitter](https://badges.gitter.im/crowfork/community.svg)](https://gitter.im/crowfork/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
[![Gitter](https://badges.gitter.im/crowfork/community.svg)](https://gitter.im/crowfork/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||||
|
|
||||||
```c++
|
```c++
|
||||||
@ -38,6 +39,8 @@ int main()
|
|||||||
- Websocket support
|
- Websocket support
|
||||||
|
|
||||||
## Still in development
|
## Still in development
|
||||||
|
- [Informational webpage](https://mrozigor.github.io/crow) (what is crow, guides, examples, etc..)
|
||||||
|
- [HTTP/2 support](https://github.com/mrozigor/crow/issues/8)
|
||||||
- ~~Built-in ORM~~
|
- ~~Built-in ORM~~
|
||||||
- Check [sqlpp11](https://github.com/rbock/sqlpp11) if you want one.
|
- Check [sqlpp11](https://github.com/rbock/sqlpp11) if you want one.
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
namespace crow
|
namespace crow
|
||||||
{
|
{
|
||||||
|
/// Hashing function for ci_map (unordered_multimap).
|
||||||
struct ci_hash
|
struct ci_hash
|
||||||
{
|
{
|
||||||
size_t operator()(const std::string& key) const
|
size_t operator()(const std::string& key) const
|
||||||
@ -22,6 +23,7 @@ namespace crow
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Equals function for ci_map (unordered_multimap).
|
||||||
struct ci_key_eq
|
struct ci_key_eq
|
||||||
{
|
{
|
||||||
bool operator()(const std::string& l, const std::string& r) const
|
bool operator()(const std::string& l, const std::string& r) const
|
||||||
|
@ -178,6 +178,8 @@ namespace crow
|
|||||||
#ifdef CROW_ENABLE_DEBUG
|
#ifdef CROW_ENABLE_DEBUG
|
||||||
static std::atomic<int> connectionCount;
|
static std::atomic<int> connectionCount;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// An HTTP connection.
|
||||||
template <typename Adaptor, typename Handler, typename ... Middlewares>
|
template <typename Adaptor, typename Handler, typename ... Middlewares>
|
||||||
class Connection
|
class Connection
|
||||||
{
|
{
|
||||||
@ -216,6 +218,7 @@ namespace crow
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The TCP socket on top of which the connection is established.
|
||||||
decltype(std::declval<Adaptor>().raw_socket())& socket()
|
decltype(std::declval<Adaptor>().raw_socket())& socket()
|
||||||
{
|
{
|
||||||
return adaptor_.raw_socket();
|
return adaptor_.raw_socket();
|
||||||
@ -336,6 +339,7 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Call the after handle middleware and send the write the response to the connection.
|
||||||
void complete_request()
|
void complete_request()
|
||||||
{
|
{
|
||||||
CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_;
|
CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_;
|
||||||
|
@ -26,12 +26,12 @@ namespace crow
|
|||||||
struct request
|
struct request
|
||||||
{
|
{
|
||||||
HTTPMethod method;
|
HTTPMethod method;
|
||||||
std::string raw_url; /// The full URL containing the host.
|
std::string raw_url; ///< The full URL containing the host.
|
||||||
std::string url; /// The Endpoint.
|
std::string url; ///< The Endpoint.
|
||||||
query_string url_params; /// The parameters associated with the request. (everything after the `?`)
|
query_string url_params; ///< The parameters associated with the request. (everything after the `?`)
|
||||||
ci_map headers;
|
ci_map headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
std::string remoteIpAddress; /// The IP address from which the request was sent.
|
std::string remoteIpAddress; ///< The IP address from which the request was sent.
|
||||||
|
|
||||||
void* middleware_context{};
|
void* middleware_context{};
|
||||||
boost::asio::io_service* io_service{};
|
boost::asio::io_service* io_service{};
|
||||||
|
@ -26,10 +26,10 @@ namespace crow
|
|||||||
template <typename Adaptor, typename Handler, typename ... Middlewares>
|
template <typename Adaptor, typename Handler, typename ... Middlewares>
|
||||||
friend class crow::Connection;
|
friend class crow::Connection;
|
||||||
|
|
||||||
int code{200}; /// The Status code for the response.
|
int code{200}; ///< The Status code for the response.
|
||||||
std::string body; /// The actual payload containing the response data.
|
std::string body; ///< The actual payload containing the response data.
|
||||||
json::wvalue json_value; /// if the response body is JSON, this would be it.
|
json::wvalue json_value; ///< if the response body is JSON, this would be it.
|
||||||
ci_map headers; /// HTTP headers.
|
ci_map headers; ///< HTTP headers.
|
||||||
|
|
||||||
/// Set the value of an existing header in the response.
|
/// Set the value of an existing header in the response.
|
||||||
void set_header(std::string key, std::string value)
|
void set_header(std::string key, std::string value)
|
||||||
|
@ -108,7 +108,7 @@ namespace crow
|
|||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
/// A read string implementation with comparison functionality.
|
||||||
struct r_string
|
struct r_string
|
||||||
: boost::less_than_comparable<r_string>,
|
: boost::less_than_comparable<r_string>,
|
||||||
boost::less_than_comparable<r_string, std::string>,
|
boost::less_than_comparable<r_string, std::string>,
|
||||||
@ -166,8 +166,8 @@ namespace crow
|
|||||||
using iterator = const char*;
|
using iterator = const char*;
|
||||||
using const_iterator = const char*;
|
using const_iterator = const char*;
|
||||||
|
|
||||||
char* s_;
|
char* s_; ///< Start.
|
||||||
mutable char* e_;
|
mutable char* e_; ///< End.
|
||||||
uint8_t owned_{0};
|
uint8_t owned_{0};
|
||||||
friend std::ostream& operator << (std::ostream& os, const r_string& s)
|
friend std::ostream& operator << (std::ostream& os, const r_string& s)
|
||||||
{
|
{
|
||||||
@ -210,6 +210,11 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// JSON read value.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Value can mean any json value, including a JSON object.
|
||||||
|
/// Read means this class is used to primarily read strings into a JSON value.
|
||||||
class rvalue
|
class rvalue
|
||||||
{
|
{
|
||||||
static const int cached_bit = 2;
|
static const int cached_bit = 2;
|
||||||
@ -289,6 +294,7 @@ namespace crow
|
|||||||
return (int)i();
|
return (int)i();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The type of the JSON value.
|
||||||
type t() const
|
type t() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -300,6 +306,7 @@ namespace crow
|
|||||||
return t_;
|
return t_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The number type of the JSON value.
|
||||||
num_type nt() const
|
num_type nt() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -311,6 +318,7 @@ namespace crow
|
|||||||
return nt_;
|
return nt_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The integer value.
|
||||||
int64_t i() const
|
int64_t i() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -327,6 +335,7 @@ namespace crow
|
|||||||
return boost::lexical_cast<int64_t>(start_, end_-start_);
|
return boost::lexical_cast<int64_t>(start_, end_-start_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The unsigned integer value.
|
||||||
uint64_t u() const
|
uint64_t u() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -341,6 +350,7 @@ namespace crow
|
|||||||
return boost::lexical_cast<uint64_t>(start_, end_-start_);
|
return boost::lexical_cast<uint64_t>(start_, end_-start_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The double precision floating-point number value.
|
||||||
double d() const
|
double d() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -350,6 +360,7 @@ namespace crow
|
|||||||
return boost::lexical_cast<double>(start_, end_-start_);
|
return boost::lexical_cast<double>(start_, end_-start_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The boolean value.
|
||||||
bool b() const
|
bool b() const
|
||||||
{
|
{
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
@ -359,6 +370,18 @@ namespace crow
|
|||||||
return t() == type::True;
|
return t() == type::True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The string value.
|
||||||
|
detail::r_string s() const
|
||||||
|
{
|
||||||
|
#ifndef CROW_JSON_NO_ERROR_CHECK
|
||||||
|
if (t() != type::String)
|
||||||
|
throw std::runtime_error("value is not string");
|
||||||
|
#endif
|
||||||
|
unescape();
|
||||||
|
return detail::r_string{start_, end_};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert escaped string character to their original form ("\\n" -> '\n').
|
||||||
void unescape() const
|
void unescape() const
|
||||||
{
|
{
|
||||||
if (*(start_-1))
|
if (*(start_-1))
|
||||||
@ -424,16 +447,6 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::r_string s() const
|
|
||||||
{
|
|
||||||
#ifndef CROW_JSON_NO_ERROR_CHECK
|
|
||||||
if (t() != type::String)
|
|
||||||
throw std::runtime_error("value is not string");
|
|
||||||
#endif
|
|
||||||
unescape();
|
|
||||||
return detail::r_string{start_, end_};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has(const char* str) const
|
bool has(const char* str) const
|
||||||
{
|
{
|
||||||
return has(std::string(str));
|
return has(std::string(str));
|
||||||
@ -615,7 +628,7 @@ namespace crow
|
|||||||
lremain_ --;
|
lremain_ --;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determines num_type from the string
|
/// determines num_type from the string.
|
||||||
void determine_num_type()
|
void determine_num_type()
|
||||||
{
|
{
|
||||||
if (t_ != type::Number)
|
if (t_ != type::Number)
|
||||||
@ -1142,26 +1155,31 @@ namespace crow
|
|||||||
return load(str.data(), str.size());
|
return load(str.data(), str.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// JSON write value.
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Value can mean any json value, including a JSON object.
|
||||||
|
/// Write means this class is used to primarily assemble JSON objects using keys and values and export those into a string.
|
||||||
class wvalue
|
class wvalue
|
||||||
{
|
{
|
||||||
friend class crow::mustache::template_t;
|
friend class crow::mustache::template_t;
|
||||||
public:
|
public:
|
||||||
type t() const { return t_; }
|
type t() const { return t_; }
|
||||||
private:
|
private:
|
||||||
type t_{type::Null};
|
type t_{type::Null}; ///< The type of the value.
|
||||||
num_type nt{num_type::Null};
|
num_type nt{num_type::Null}; ///< The specific type of the number if \ref t_ is a number.
|
||||||
union {
|
union {
|
||||||
double d;
|
double d;
|
||||||
int64_t si;
|
int64_t si;
|
||||||
uint64_t ui {};
|
uint64_t ui {};
|
||||||
} num;
|
} num; ///< Value if type is a number.
|
||||||
std::string s;
|
std::string s; ///< Value if type is a string.
|
||||||
std::unique_ptr<std::vector<wvalue>> l;
|
std::unique_ptr<std::vector<wvalue>> l; ///< Value if type is a list.
|
||||||
std::unique_ptr<std::unordered_map<std::string, wvalue>> o;
|
std::unique_ptr<std::unordered_map<std::string, wvalue>> o; ///< Value if type is a JSON object.
|
||||||
public:
|
public:
|
||||||
|
|
||||||
wvalue() {}
|
wvalue() {}
|
||||||
|
/// Create a write value from a read value (useful for editing JSON strings).
|
||||||
wvalue(const rvalue& r)
|
wvalue(const rvalue& r)
|
||||||
{
|
{
|
||||||
t_ = r.t();
|
t_ = r.t();
|
||||||
@ -1215,6 +1233,7 @@ namespace crow
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used for compatibility, same as \ref reset()
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
|
@ -8,6 +8,8 @@ namespace crow
|
|||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
template <typename ... Middlewares>
|
template <typename ... Middlewares>
|
||||||
struct partial_context
|
struct partial_context
|
||||||
: public black_magic::pop_back<Middlewares...>::template rebind<partial_context>
|
: public black_magic::pop_back<Middlewares...>::template rebind<partial_context>
|
||||||
@ -24,6 +26,8 @@ namespace crow
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct partial_context<>
|
struct partial_context<>
|
||||||
{
|
{
|
||||||
@ -31,9 +35,13 @@ namespace crow
|
|||||||
using partial = partial_context;
|
using partial = partial_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <int N, typename Context, typename Container, typename CurrentMW, typename ... Middlewares>
|
template <int N, typename Context, typename Container, typename CurrentMW, typename ... Middlewares>
|
||||||
bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
|
bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename ... Middlewares>
|
template <typename ... Middlewares>
|
||||||
struct context : private partial_context<Middlewares...>
|
struct context : private partial_context<Middlewares...>
|
||||||
//struct context : private Middlewares::context... // simple but less type-safe
|
//struct context : private Middlewares::context... // simple but less type-safe
|
||||||
|
@ -49,6 +49,7 @@ namespace crow
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A mustache template object.
|
||||||
class template_t
|
class template_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
namespace crow
|
namespace crow
|
||||||
{
|
{
|
||||||
|
/// A wrapper for `nodejs/http-parser`.
|
||||||
|
|
||||||
|
/// Used to generate a \ref crow.request from the TCP socket buffer.
|
||||||
|
///
|
||||||
template <typename Handler>
|
template <typename Handler>
|
||||||
struct HTTPParser : public http_parser
|
struct HTTPParser : public http_parser
|
||||||
{
|
{
|
||||||
@ -93,6 +97,7 @@ namespace crow
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return false on error
|
// return false on error
|
||||||
|
/// Parse a buffer into the different sections of an HTTP request.
|
||||||
bool feed(const char* buffer, int length)
|
bool feed(const char* buffer, int length)
|
||||||
{
|
{
|
||||||
const static http_parser_settings settings_{
|
const static http_parser_settings settings_{
|
||||||
@ -137,6 +142,7 @@ namespace crow
|
|||||||
handler_->handle();
|
handler_->handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take the parsed HTTP request data and convert it to a \ref crow.request
|
||||||
request to_request() const
|
request to_request() const
|
||||||
{
|
{
|
||||||
return request{(HTTPMethod)method, std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
|
return request{(HTTPMethod)method, std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
|
||||||
@ -159,9 +165,9 @@ namespace crow
|
|||||||
std::string header_field;
|
std::string header_field;
|
||||||
std::string header_value;
|
std::string header_value;
|
||||||
ci_map headers;
|
ci_map headers;
|
||||||
query_string url_params;
|
query_string url_params; ///< What comes after the `?` in the URL.
|
||||||
std::string body;
|
std::string body;
|
||||||
|
|
||||||
Handler* handler_;
|
Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection).
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -287,6 +287,7 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t
|
|||||||
|
|
||||||
namespace crow
|
namespace crow
|
||||||
{
|
{
|
||||||
|
/// A class to represent any data coming after the `?` in the request URL into key-value pairs.
|
||||||
class query_string
|
class query_string
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -17,6 +17,10 @@
|
|||||||
|
|
||||||
namespace crow
|
namespace crow
|
||||||
{
|
{
|
||||||
|
/// A base class for all rules.
|
||||||
|
|
||||||
|
/// Used to provide a common interface for code dealing with different types of rules.
|
||||||
|
/// A Rule provides a URL, allowed HTTP methods, and handlers.
|
||||||
class BaseRule
|
class BaseRule
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -267,6 +271,10 @@ namespace crow
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A rule dealing with websockets.
|
||||||
|
|
||||||
|
/// Provides the interface for the user to put in the necessary handlers for a websocket to work.
|
||||||
|
///
|
||||||
class WebSocketRule : public BaseRule
|
class WebSocketRule : public BaseRule
|
||||||
{
|
{
|
||||||
using self_t = WebSocketRule;
|
using self_t = WebSocketRule;
|
||||||
@ -340,6 +348,9 @@ namespace crow
|
|||||||
std::function<bool(const crow::request&)> accept_handler_;
|
std::function<bool(const crow::request&)> accept_handler_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Allows the user to assign parameters using functions.
|
||||||
|
///
|
||||||
|
/// `rule.name("name").methods(HTTPMethod::POST)`
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct RuleParameterTraits
|
struct RuleParameterTraits
|
||||||
{
|
{
|
||||||
@ -373,6 +384,7 @@ namespace crow
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A rule that can change its parameters during runtime.
|
||||||
class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
|
class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -447,6 +459,7 @@ namespace crow
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Default rule created when CROW_ROUTE is called.
|
||||||
template <typename ... Args>
|
template <typename ... Args>
|
||||||
class TaggedRule : public BaseRule, public RuleParameterTraits<TaggedRule<Args...>>
|
class TaggedRule : public BaseRule, public RuleParameterTraits<TaggedRule<Args...>>
|
||||||
{
|
{
|
||||||
@ -560,6 +573,7 @@ namespace crow
|
|||||||
|
|
||||||
const int RULE_SPECIAL_REDIRECT_SLASH = 1;
|
const int RULE_SPECIAL_REDIRECT_SLASH = 1;
|
||||||
|
|
||||||
|
/// A search tree.
|
||||||
class Trie
|
class Trie
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -888,6 +902,7 @@ public:
|
|||||||
std::vector<Node> nodes_;
|
std::vector<Node> nodes_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Handles matching requests to existing rules and upgrade requests.
|
||||||
class Router
|
class Router
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -931,7 +946,7 @@ public:
|
|||||||
per_methods_[method].trie.add(rule, per_methods_[method].rules.size() - 1);
|
per_methods_[method].trie.add(rule, per_methods_[method].rules.size() - 1);
|
||||||
|
|
||||||
// directory case:
|
// directory case:
|
||||||
// request to `/about' url matches `/about/' rule
|
// request to '/about' url matches '/about/' rule
|
||||||
if (has_trailing_slash)
|
if (has_trailing_slash)
|
||||||
{
|
{
|
||||||
per_methods_[method].trie.add(rule_without_trailing_slash, RULE_SPECIAL_REDIRECT_SLASH);
|
per_methods_[method].trie.add(rule_without_trailing_slash, RULE_SPECIAL_REDIRECT_SLASH);
|
||||||
|
@ -24,6 +24,7 @@ namespace crow
|
|||||||
return i >= len ? throw OutOfRange(i, len) : i;
|
return i >= len ? throw OutOfRange(i, len) : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A constant string implementation.
|
||||||
class const_str
|
class const_str
|
||||||
{
|
{
|
||||||
const char * const begin_;
|
const char * const begin_;
|
||||||
|
Loading…
Reference in New Issue
Block a user