mirror of
https://github.com/matrix-construct/construct
synced 2024-06-02 10:08:56 +02:00
ircd: Add additional comments / documentation.
This commit is contained in:
parent
df4915dec4
commit
61eb6d34df
|
@ -26,6 +26,43 @@
|
|||
#pragma once
|
||||
#define HAVE_IRCD_ALLOCATOR_H
|
||||
|
||||
/// Suite of custom allocator templates for special behavior and optimization
|
||||
///
|
||||
/// These tools can be used as alternatives to the standard allocator. Most
|
||||
/// templates implement the std::allocator concept and can be used with
|
||||
/// std:: containers by specifying them in the container's template parameter.
|
||||
///
|
||||
/// The C++ standard library assumes the availability of dynamic memory. This
|
||||
/// is a reasonable assumption to enjoy a huge simplification of the std::
|
||||
/// interface. Standard dynamic allocation can also be fast and unintrusive for
|
||||
/// a vast majority of cases. Unfortunately STL container's use of allocators
|
||||
/// can lead to a huge number of allocations and frees and in many trivial
|
||||
/// circumstances which won't be optimized as well as they ought to be.
|
||||
/// Furthermore, the std::allocator using `new` requires synchronization in
|
||||
/// multi-threaded environments. tcmalloc may be used for IRCd but its presence
|
||||
/// and performance should not be blindly assumed either. The fact remains,
|
||||
/// containers are very nice to work with but there is room for optimizing
|
||||
/// their backend through the allocator template.
|
||||
///
|
||||
/// The ircd::allocator::fixed is the prototypical justification for these
|
||||
/// tools. It allows you to build a memory pool with a size known at compile-
|
||||
/// time at the place of your choosing (i.e the stack) for any STL container. A
|
||||
/// simple std::vector constructed on the stack with a fixed number of elements
|
||||
/// known at construction time won't otherwise magically optimize away the
|
||||
/// allocation for the elements; worse, a non-contiguous container like
|
||||
/// std::list, std::map or std::set will conduct allocations for each modifying
|
||||
/// operation. Having the fixed pool on the stack plugged into these containers
|
||||
/// trivializes those requests and releases of memory.
|
||||
///
|
||||
/// The ircd::allocator::dynamic performs a single allocation of a contiguous
|
||||
/// memory block with a size specified at runtime. This block can then be used
|
||||
/// by a container.
|
||||
///
|
||||
/// The ircd::allocator::node is an interface for allowing one to manually deal
|
||||
/// with the elements of an STL container similar to a C style container where
|
||||
/// a "node" is constructed at the user's discretion and then inserted and
|
||||
/// removed from the container.
|
||||
///
|
||||
namespace ircd::allocator
|
||||
{
|
||||
struct state;
|
||||
|
@ -34,6 +71,16 @@ namespace ircd::allocator
|
|||
template<class T> struct node;
|
||||
};
|
||||
|
||||
/// Internal state structure for some of these tools. This is a very small and
|
||||
/// simple interface to a bit array representing the availability of an element
|
||||
/// in a pool of elements. The actual array of the proper number of bits must
|
||||
/// be supplied by the user of the state. The allocator using this interface
|
||||
/// can use any strategy to flip these bits but the default next()/allocate()
|
||||
/// functions scan for the next available contiguous block of zero bits and
|
||||
/// then wrap around when reaching the end of the array. Once a full iteration
|
||||
/// of the array is made without finding satisfaction, an std::bad_alloc is
|
||||
/// thrown.
|
||||
///
|
||||
struct ircd::allocator::state
|
||||
{
|
||||
using word_t = unsigned long long;
|
||||
|
@ -63,6 +110,15 @@ struct ircd::allocator::state
|
|||
{}
|
||||
};
|
||||
|
||||
/// The fixed allocator creates a block of data with a size known at compile-
|
||||
/// time. This structure itself is the state object for the actual allocator
|
||||
/// instance used in the container. Create an instance of this structure,
|
||||
/// perhaps on your stack. Then specify the ircd::allocator::fixed::allocator
|
||||
/// in the template for the container. Then pass a reference to the state
|
||||
/// object as an argument to the container when constructing. STL containers
|
||||
/// have an overloaded constructor for this when specializing the allocator
|
||||
/// template as we are here.
|
||||
///
|
||||
template<class T,
|
||||
size_t max>
|
||||
struct ircd::allocator::fixed
|
||||
|
@ -82,6 +138,14 @@ struct ircd::allocator::fixed
|
|||
{}
|
||||
};
|
||||
|
||||
/// The actual allocator template as used by the container.
|
||||
///
|
||||
/// This has to be a very light, small and copyable object which cannot hold
|
||||
/// our actual memory or state (lest we just use dynamic allocation for that!)
|
||||
/// which means we have to pass this a reference to our ircd::allocator::fixed
|
||||
/// instance. We can do that through the container's custom-allocator overload
|
||||
/// at its construction.
|
||||
///
|
||||
template<class T,
|
||||
size_t size>
|
||||
struct ircd::allocator::fixed<T, size>::allocator
|
||||
|
@ -157,6 +221,14 @@ allocator()
|
|||
return { *this };
|
||||
}
|
||||
|
||||
/// The dynamic allocator provides a pool of a fixed size known at runtime.
|
||||
///
|
||||
/// This allocator conducts a single new and delete for a pool allowing an STL
|
||||
/// container to operate without interacting with the rest of the system and
|
||||
/// without fragmentation. This is not as useful as the allocator::fixed in
|
||||
/// practice as the standard allocator is as good as this in many cases. This
|
||||
/// is still available as an analog to the fixed allocator in this suite.
|
||||
///
|
||||
template<class T>
|
||||
struct ircd::allocator::dynamic
|
||||
:state
|
||||
|
@ -188,6 +260,10 @@ struct ircd::allocator::dynamic
|
|||
}
|
||||
};
|
||||
|
||||
/// The actual template passed to containers for using the dynamic allocator.
|
||||
///
|
||||
/// See the notes for ircd::allocator::fixed::allocator for details.
|
||||
///
|
||||
template<class T>
|
||||
struct ircd::allocator::dynamic<T>::allocator
|
||||
{
|
||||
|
@ -260,6 +336,23 @@ allocator()
|
|||
return { *this };
|
||||
}
|
||||
|
||||
/// Allows elements of an STL container to be manually handled by the user.
|
||||
///
|
||||
/// C library containers usually allow the user to manually construct a node
|
||||
/// and then insert it and remove it from the container. With STL containers
|
||||
/// we can use devices like allocator::fixed, but what if we don't want to have
|
||||
/// a bound on the allocator's size either at compile time or at runtime? What
|
||||
/// if we simply want to manually handle the container's elements, like on the
|
||||
/// stack, and in different frames, and then manipulate the container -- or
|
||||
/// even better and safer: have the elements add and remove themselves while
|
||||
/// storing the container's node data too?
|
||||
///
|
||||
/// This device helps the user achieve that by simply providing a variable
|
||||
/// set by the user indicating where the 'next' block of memory is when the
|
||||
/// container requests it. Whether the container is requesting memory which
|
||||
/// should be fulfilled by that 'next' block must be ensured and asserted by
|
||||
/// the user, but this is likely the case.
|
||||
///
|
||||
template<class T>
|
||||
struct ircd::allocator::node
|
||||
{
|
||||
|
@ -271,6 +364,10 @@ struct ircd::allocator::node
|
|||
node() = default;
|
||||
};
|
||||
|
||||
/// The actual template passed to containers for using the allocator.
|
||||
///
|
||||
/// See the notes for ircd::allocator::fixed::allocator for details.
|
||||
///
|
||||
template<class T>
|
||||
struct ircd::allocator::node<T>::allocator
|
||||
{
|
||||
|
|
|
@ -86,8 +86,20 @@ class ircd::fmt::specifier
|
|||
// User API
|
||||
//
|
||||
|
||||
// * The arguments are not restricted by stdarg limitations. You can pass a real std::string.
|
||||
// * The function participates in the custom protocol-safe ruleset.
|
||||
/// Typesafe snprintf() from formal grammar and RTTI.
|
||||
///
|
||||
/// This function accepts a format string and a variable number of arguments
|
||||
/// composing formatted null-terminated output in the provided output buffer.
|
||||
/// The format string is compliant with standard snprintf() (TODO: not yet).
|
||||
/// The type information of the arguments is grabbed from the variadic template
|
||||
/// and references are passed to the formal output grammars. This means you can
|
||||
/// pass an std::string directly without calling c_str(), as well as pass a
|
||||
/// non-null-terminated string_view safely.
|
||||
///
|
||||
/// Furthermore, other features of ircd::fmt enable custom format specifiers
|
||||
/// and handling of types not recognized by existing grammars through this
|
||||
/// function.
|
||||
///
|
||||
class ircd::fmt::snprintf
|
||||
{
|
||||
const char *fstart; // Current running position in the fmtstr
|
||||
|
@ -137,6 +149,17 @@ struct ircd::fmt::sprintf
|
|||
}{}
|
||||
};
|
||||
|
||||
/// A complement to fmt::snprintf() accepting an already-made va_rtti.
|
||||
///
|
||||
/// This function has no variadic template; instead it accepts the type
|
||||
/// which would be composed by such a variadic template called
|
||||
/// ircd::va_rtti directly.
|
||||
///
|
||||
/// ircd::va_rtti is a lightweight pairing of argument pointers to runtime
|
||||
/// type indexes. ircd::va_rtti is not a template itself because its purpose
|
||||
/// is to bring this type information out of the header files to where the
|
||||
/// grammar is instantiated.
|
||||
///
|
||||
struct ircd::fmt::vsnprintf
|
||||
:snprintf
|
||||
{
|
||||
|
|
|
@ -95,6 +95,7 @@ enum ircd::http::code
|
|||
INSUFFICIENT_STORAGE = 507,
|
||||
};
|
||||
|
||||
/// Root exception for HTTP.
|
||||
struct ircd::http::error
|
||||
:ircd::error
|
||||
{
|
||||
|
@ -104,6 +105,13 @@ struct ircd::http::error
|
|||
error(const enum code &, std::string content = {});
|
||||
};
|
||||
|
||||
/// Represents a single \r\n delimited line used in HTTP.
|
||||
///
|
||||
/// This object is just a string_view of that line. The actual data backing
|
||||
/// that view is the responsibility of the user. This object is constructed
|
||||
/// with an ircd::parse::capstan argument which is used by the formal grammar
|
||||
/// in the constructor.
|
||||
///
|
||||
struct ircd::http::line
|
||||
:string_view
|
||||
{
|
||||
|
@ -120,6 +128,14 @@ namespace ircd::http
|
|||
using header = line::header;
|
||||
}
|
||||
|
||||
/// Represents a 'request line' or the first line a client sends to a server.
|
||||
///
|
||||
/// This is a dual-use class. For HTTP clients, one may simply connect the
|
||||
/// members to the proper strings and then pass this structure to a function
|
||||
/// making a client request. For HTTP servers, pass an http::line to the ctor
|
||||
/// and the formal grammar will set the members appropriately. The actual data
|
||||
/// behind these members is the responsibility of the user.
|
||||
///
|
||||
struct ircd::http::line::request
|
||||
{
|
||||
string_view method;
|
||||
|
@ -132,6 +148,13 @@ struct ircd::http::line::request
|
|||
request() = default;
|
||||
};
|
||||
|
||||
/// Represents a 'response line' or the first line a server sends to a client.
|
||||
///
|
||||
/// This is a dual-use class and symmetric to the http::line::request class.
|
||||
/// Servers may set the members and then use this object to respond to a client
|
||||
/// while clients should provide an http::line to the constructor which will
|
||||
/// fill in the members.
|
||||
///
|
||||
struct ircd::http::line::response
|
||||
{
|
||||
string_view version;
|
||||
|
@ -142,6 +165,11 @@ struct ircd::http::line::response
|
|||
response() = default;
|
||||
};
|
||||
|
||||
/// Represents a single key/value pair in a query string.
|
||||
///
|
||||
/// This is used by the ircd::http::query::string object when parsing query
|
||||
/// strings.
|
||||
///
|
||||
struct ircd::http::query
|
||||
:std::pair<string_view, string_view>
|
||||
{
|
||||
|
@ -154,8 +182,14 @@ struct ircd::http::query
|
|||
query() = default;
|
||||
};
|
||||
|
||||
// Query string is read as a complete string off the tape (into request.query) and
|
||||
// not parsed further. To make queries into that string use this class to view it.
|
||||
/// Tool for parsing an HTTP query string.
|
||||
///
|
||||
/// Query string is read as a complete string off the tape (into request.query)
|
||||
/// and not parsed further. To make queries into that string use this class to
|
||||
/// view it. Once this object is constructed by viewing the whole query string,
|
||||
/// the member functions invoke the formal grammar to get individual key/value
|
||||
/// pairs.
|
||||
///
|
||||
struct ircd::http::query::string
|
||||
:string_view
|
||||
{
|
||||
|
@ -168,6 +202,12 @@ struct ircd::http::query::string
|
|||
using string_view::string_view;
|
||||
};
|
||||
|
||||
/// Represents an HTTP header key/value pair.
|
||||
///
|
||||
/// This is a dual-use class. Those sending headers will simply fill in the
|
||||
/// components of the std::pair. Those receiving headers can pass the ctor an
|
||||
/// ircd::http::line which will construct the pair using the formal grammars.
|
||||
///
|
||||
struct ircd::http::line::header
|
||||
:std::pair<string_view, string_view>
|
||||
{
|
||||
|
@ -179,7 +219,12 @@ struct ircd::http::line::header
|
|||
header() = default;
|
||||
};
|
||||
|
||||
// HTTP headers are read once off the tape and proffered to the closure.
|
||||
/// This device allows parsing HTTP headers directly off the wire without state
|
||||
///
|
||||
/// The constructor of this object contains the grammar to read HTTP headers
|
||||
/// from the capstan and then proffer them one by one to the provided closure,
|
||||
/// that's all it does.
|
||||
///
|
||||
struct ircd::http::headers
|
||||
:string_view
|
||||
{
|
||||
|
@ -189,9 +234,16 @@ struct ircd::http::headers
|
|||
headers(parse::capstan &, const closure & = {});
|
||||
};
|
||||
|
||||
// Use the request::content / response::content wrappers. They ensure the proper amount
|
||||
// of content is read and the tape is in the right position for the next request
|
||||
// with exception safety.
|
||||
/// Represents the content of an HTTP request after the head.
|
||||
///
|
||||
/// Use the request::content / response::content wrappers. They ensure the
|
||||
/// proper amount of content is read and the tape is in the right position
|
||||
/// for the next request with exception safety. In other words, this object
|
||||
/// ensures the capstan is in the proper place for the next request no matter
|
||||
/// what happens; whether an exception happened, or whether the user simply
|
||||
/// didn't care to read the content. The capstan MUST advance Content-Length
|
||||
/// bytes in any case.
|
||||
///
|
||||
struct ircd::http::content
|
||||
:string_view
|
||||
{
|
||||
|
@ -204,6 +256,8 @@ struct ircd::http::content
|
|||
content() = default;
|
||||
};
|
||||
|
||||
/// HTTP response suite. Functionality to send and receive responses.
|
||||
///
|
||||
struct ircd::http::response
|
||||
{
|
||||
struct head;
|
||||
|
@ -247,6 +301,8 @@ struct ircd::http::response::chunked::chunk
|
|||
chunk(chunked &, const const_buffer &);
|
||||
};
|
||||
|
||||
/// Represents an HTTP response head. This is for receiving responses only.
|
||||
///
|
||||
struct ircd::http::response::head
|
||||
:line::response
|
||||
{
|
||||
|
@ -258,6 +314,8 @@ struct ircd::http::response::head
|
|||
head(parse::capstan &pc, const headers::closure &c = {});
|
||||
};
|
||||
|
||||
/// Represents an HTTP response content. This is for receiving only.
|
||||
///
|
||||
struct ircd::http::response::content
|
||||
:http::content
|
||||
{
|
||||
|
@ -276,6 +334,8 @@ struct ircd::http::response::content
|
|||
content() = default;
|
||||
};
|
||||
|
||||
/// HTTP request suite. Functionality to send and receive requests.
|
||||
///
|
||||
struct ircd::http::request
|
||||
{
|
||||
struct head;
|
||||
|
@ -300,6 +360,8 @@ struct ircd::http::request
|
|||
const headers::closure & = {});
|
||||
};
|
||||
|
||||
/// Represents an HTTP request head. This is only for receiving requests.
|
||||
///
|
||||
struct ircd::http::request::head
|
||||
:line::request
|
||||
{
|
||||
|
@ -314,6 +376,8 @@ struct ircd::http::request::head
|
|||
head(parse::capstan &pc, const headers::closure &c = {});
|
||||
};
|
||||
|
||||
/// Represents an HTTP request content. This is only for receiving content.
|
||||
///
|
||||
struct ircd::http::request::content
|
||||
:http::content
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue