{"id":5117,"date":"2017-01-09T21:41:19","date_gmt":"2017-01-09T21:41:19","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/memory-pool-allocators-with-jonathan-mueller\/"},"modified":"2023-09-18T17:23:22","modified_gmt":"2023-09-18T17:23:22","slug":"memory-pool-allocators-with-jonathan-mueller","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/memory-pool-allocators-with-jonathan-mueller\/","title":{"rendered":"Memory Pool Allocators by Jonathan M\u00fcller"},"content":{"rendered":"<p>After I have written a few posts about <a href=\"https:\/\/www.modernescpp.com\/index.php\/tag\/memory\">memory management <\/a>in C++, I&#8217;m very glad to present Jonathan M\u00fcller, which will write a guest post about his implementation of the <a href=\"https:\/\/github.com\/foonathan\/memory\">memory<\/a> library. He will explain to us his concepts about his design. Jonathan is known as an expert in memory management in the C++ community. In the&nbsp; <a href=\"http:\/\/cppcast.com\/2016\/06\/jonathan-muller\/\">59 <\/a>episodes, he presented his ideas to a worldwide audience.<\/p>\n<p><!--more--><\/p>\n<h2>The motivation<\/h2>\n<p>At first, there is the question. Why did Jonathan write a library in C++ for memory management? Of course, he answered the question himself on his GitHub project <a href=\"https:\/\/github.com\/foonathan\/memory\">memory:<\/a><\/p>\n<p>&#8220;<em>The C++ STL allocator model has various flaws. For example, they are fixed to a certain type, because they are almost necessarily required to be templates. So you can&#8217;t easily share a single allocator for multiple types. In addition, you can only get a copy from the containers and not the original allocator object. At least with C++11 they are allowed to be stateful and so can be made object not instance based. But still, the model has many flaws. Over the course of the years, many solutions have been proposed. for example <a href=\"http:\/\/www.open-std.org\/jtc1\/sc22\/wg21\/docs\/papers\/2007\/n2271.html\">EASTL<\/a>. This library is another. But instead of trying to change the STL, it works with the current implementation<\/em>.&#8221;<\/p>\n<p>But that is not the complete answer. More promising is his provoking statement about the performance of his library, which he proves in four&nbsp;<a href=\"https:\/\/foonathan.github.io\/blog\/2016\/03\/18\/boosting-pools-1.html\">very readable posts<\/a>:&nbsp;<strong>How I have beaten Boost.Pool.<\/strong> In particular, his explanations of the different optimization strategies for memory allocations provide deep insight and have a broader focus. <strong><br \/> <\/strong><\/p>\n<p>But now, let&#8217;s start with Jonathan M\u00fcller&#8217;s post, translated from German to English by Rainer Grimm.<\/p>\n<\/p>\n<h2>Memory pool allocator<\/h2>\n<p>A memory pool allocator is a generally usable and fast allocator. It allocates only big memory blocks and divides them into equally sized pieces. All free pieces are stored in a so-called <strong>free list<\/strong>.&nbsp; The allocation removes the first element of the<strong class=\"moz-txt-star\"><span class=\"moz-txt-tag\"> <\/span>free list<span class=\"moz-txt-tag\"><\/span><\/strong> and returns it. Deallocation pushes it at the back. That is relatively fast, but you can only use it for fixed-size pieces. If not, you have fragmentation issues and therefore need a long time for finding the fitting piece.<\/p>\n<p>Now, I will show how you can use the pool implementation of my <a href=\"https:\/\/github.com\/foonathan\/memory\">memory library<\/a> for your own allocation.<\/p>\n<p style=\"padding-left: 30px;\">memory is a library that provides different allocators and their infrastructure without issues. The current version is 0.x and, therefore, in the development phase.<\/p>\n<h3>The<span style=\"font-family: courier new,courier;\"> memory pool<\/span><\/h3>\n<p>If you&#8217;ve <a href=\"https:\/\/github.com\/foonathan\/memory\">installed<\/a> my library, the memory pool will be quite easy to use.<\/p>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/memory_pool.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/namespace_alias.hpp&gt; <\/span><span style=\"color: #008000;\">\/\/ (1)<\/span>\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main()\r\n{\r\n    memory::memory_pool&lt;&gt; pool(16, 4096); <span style=\"color: #008000;\">\/\/ (2)<\/span>\r\n    <span style=\"color: #2b91af;\">void<\/span>* node = pool.allocate_node(); <span style=\"color: #008000;\">\/\/ (3)<\/span>\r\n    <span style=\"color: #008000;\">\/\/ ...<\/span>\r\n    pool.deallocate_node(node); <span style=\"color: #008000;\">\/\/ (4)<\/span>\r\n} \r\n<\/pre>\n<p>After you have included the necessary headers (1), you can use a memory pool (2).&nbsp; The header<span style=\"font-family: courier new,courier;\"> namespace_alias.hpp<\/span> automatically gives you the <a href=\"https:\/\/foonathan.github.io\/blog\/2016\/01\/26\/namespace-alias.html\">alias<\/a> for the long namespace names<span style=\"font-family: courier new,courier;\"> foonathan::memory. <\/span>The constructor has two parameters. The first one is the size of each block in the <strong>free list,<\/strong> the so-called <strong>node<\/strong> <strong>size.<\/strong> The second one is the size of the big memory block, which will be divided into<span style=\"font-family: courier new,courier;\"> <\/span>4KiB parts.<\/p>\n<p>Now, you can request small memory blocks from the pool, so-called <strong>nodes<\/strong> (3), and release them (4). Each <strong>node<\/strong> is as big as specified in the constructor. In this example, 16 Bytes. Of course, the big memory block&#8217;s release in the pool&#8217;s destructor will automatically release all <strong>nodes<\/strong> &#8211; even if there was no call <span style=\"font-family: courier new,courier;\">deallocate_node().<\/span><\/p>\n<p>But it is quite tedious to use the pool in such a way. Therefore, the concept of <span style=\"font-family: courier new,courier;\">RawAllocator <\/span>comes to our rescue. This is the critical abstraction.<\/p>\n<h3>The <span style=\"font-family: courier new,courier;\">RawAllocator<\/span><\/h3>\n<p>In a previous chapter, the concept of the Allocator was presented. With it, you can adjust the memory requirements of the STL containers. The allocator concepts are not&nbsp;<a href=\"https:\/\/foonathan.github.io\/blog\/2015\/10\/05\/allocatorawarecontainer-propagation-pitfalls.html\">so easy to get<\/a>, and it combines the creation of the object with the allocation of the memory. That is usually not necessary. Most of the time, you only want to adjust how the memory is managed. This is the use case for <a href=\"https:\/\/foonathan.github.io\/doc\/memory\/md_doc_concepts.html#concept_rawallocator\">RawAllocator.<\/a><\/p>\n<p> A <span style=\"font-family: courier new,courier;\">RawAllocator<\/span> has the following interface:<\/p>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0000ff;\">struct<\/span> raw_allocator\r\n{\r\n    <span style=\"color: #0000ff;\">using<\/span> is_stateful = std::integral_constant&lt;<span style=\"color: #2b91af;\">bool<\/span>, Value&gt;; <span style=\"color: #008000;\">\/\/ optional, default is std::is_empty<\/span>\r\n\r\n    <span style=\"color: #2b91af;\">void<\/span>* allocate_node(std::<span style=\"color: #2b91af;\">size_t<\/span> size, std::<span style=\"color: #2b91af;\">size_t<\/span> alignment); <span style=\"color: #008000;\">\/\/ required, allocates memory<\/span>\r\n    <span style=\"color: #2b91af;\">void<\/span> deallocate_node(<span style=\"color: #2b91af;\">void<\/span> *node, std::<span style=\"color: #2b91af;\">size_t<\/span> size, std::<span style=\"color: #2b91af;\">size_t<\/span> alignment) noexcept; <span style=\"color: #008000;\">\/\/ required: releases memory<\/span>\r\n\r\n    <span style=\"color: #2b91af;\">void<\/span>* allocate_array(std::<span style=\"color: #2b91af;\">size_t<\/span> count, std::<span style=\"color: #2b91af;\">size_t<\/span> size, std::<span style=\"color: #2b91af;\">size_t<\/span> alignment); <span style=\"color: #008000;\">\/\/ optional: invokes by default allocate_node() <\/span>\r\n    <span style=\"color: #2b91af;\">void<\/span> deallocate_array(<span style=\"color: #2b91af;\">void<\/span> *ptr, std::<span style=\"color: #2b91af;\">size_t<\/span> count, std::<span style=\"color: #2b91af;\">size_t<\/span> size, std::<span style=\"color: #2b91af;\">size_t<\/span> alignment) noexcept; <span style=\"color: #008000;\">\/\/ optional: invokes by default deallocate_node()<\/span>\r\n\r\n    std::<span style=\"color: #2b91af;\">size_t<\/span> max_node_size() <span style=\"color: #0000ff;\">const<\/span>; <span style=\"color: #008000;\">\/\/ optional: returns by default the maximum value<\/span>\r\n    std::<span style=\"color: #2b91af;\">size_t<\/span> max_array_size() <span style=\"color: #0000ff;\">const<\/span>; <span style=\"color: #008000;\">\/\/ optional: returns by default max_node_size()<\/span>\r\n    std::<span style=\"color: #2b91af;\">size_t<\/span> max_alignment() <span style=\"color: #0000ff;\">const<\/span>; <span style=\"color: #008000;\">\/\/ optional: returns by default maximum alginment, e.g.: alignof(std::max_align_t)<\/span>\r\n}\r\n<\/pre>\n<p style=\"padding-left: 30px;\">The interface is quite similar to the new <a href=\"http:\/\/en.cppreference.com\/w\/cpp\/memory\/memory_resource)\">std::pmr::memory_resource<\/a> but is not implemented with inheritance. Therefore, the <span style=\"font-family: courier new,courier;\">RawAllocator<\/span> is, by default, part of the type and can only optionally be <strong class=\"moz-txt-star\"><span class=\"moz-txt-tag\"><\/span>type erased<span class=\"moz-txt-tag\"> <\/span><\/strong>by using the <span style=\"font-family: courier new,courier;\">any_allocator_reference <\/span>class.<span style=\"font-family: courier new,courier;\"> <\/span><\/p>\n<p>Most interface parts are optional and must only be implemented for special use cases. Although the <span style=\"font-family: courier new,courier;\">memory_pool<\/span> does not implement the interface, it is a <span style=\"font-family: courier new,courier;\">RawAllocator.<\/span> This is possible because each access is via the <span style=\"font-family: courier new,courier;\">memory::allocator_traits<\/span>, which are specialized by the <span style=\"font-family: courier new,courier;\">memory_pool.<\/span><\/p>\n<p>To use the <span style=\"font-family: courier new,courier;\">RawAllocator<\/span> in the STL containers, there is the adapter <span style=\"font-family: courier new,courier;\">std_allocator<\/span> which gets a <span style=\"font-family: courier new,courier;\">RawAllocator<\/span> and adjusts it to the interface of an <span style=\"font-family: courier new,courier;\">Allocator.<\/span> <span style=\"font-family: courier new,courier;\">Allocator<\/span> has to be copyable, but <span style=\"font-family: courier new,courier;\">RawAllocator<\/span>sg is not. Therefore, it stores the <span style=\"font-family: courier new,courier;\">RawAllocator<\/span> by reference.<\/p>\n<p>Because memory pools have issues with the requirements of an array, they are ideal candidates for <span style=\"font-family: courier new,courier;\">node-based containers<\/span>. Here is an example:<span style=\"font-family: courier new,courier;\"><\/span><\/p>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0000ff;\">#include &lt;set&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/container.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/memory_pool.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/namespace_alias.hpp&gt;<\/span>\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main()\r\n{\r\n    memory::memory_pool&lt;&gt; pool(memory::set_node_size&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;::value, 4096); <span style=\"color: #008000;\">\/\/ (1)<\/span>\r\n    memory::set&lt;<span style=\"color: #2b91af;\">int<\/span>, decltype(pool)&gt; set(pool); <span style=\"color: #008000;\">\/\/ (2)<\/span>\r\n    set.insert(3);\r\n    <span style=\"color: #008000;\">\/\/ ...<\/span>\r\n} \r\n<\/pre>\n<p>You can create &#8211; as previously &#8211; your pool (1). The given<strong> node size<\/strong> is exactly the size that a <span style=\"font-family: courier new,courier;\">std::set&lt;int&gt;<\/span> needs. Now I use this size for the set in (2). The type of container is <span style=\"font-family: courier new,courier;\">memory::set.<\/span> This is not a new implementation of a <span style=\"font-family: courier new,courier;\">std::set<\/span> but only a template alias. In this case a <strong>template alias<\/strong> for <span style=\"font-family: Courier New;\">std::set&lt;int, std::less&lt;int&gt;, memory::std_allocator&lt;int, decltype(pool)&gt;&gt;<\/span>. Therefore, a std::set&lt;int&gt; uses the pool through the <span style=\"font-family: Courier New;\">std_allocator<\/span>. The called constructor is the regular constructor of <span style=\"font-family: Courier New;\">std::set<\/span>. We use the fact that a RawAllocator can implicitly create the memory::std_allocator.<\/p>\n<p>Now, the usage of the set is as always. Our pool does all allocation.<\/p>\n<h3>Internally adjustment of the pool allocation<\/h3>\n<p>As I previously mentioned, a pool request a big memory block and divides it into small pieces. By default, it uses <span style=\"font-family: Courier New;\">memory::heap_allocator for that. <\/span>This <span style=\"font-family: courier new, courier;\">RawAllocator <\/span>delegates its task to OS-specific functions such as <span style=\"font-family: Courier New;\">HeapAlloc()<\/span> on Windows.<\/p>\n<p>But you can use template arguments to adjust the internal allocator.<\/p>\n<p>One combination of allocators is quite helpful. For example, we want to have a <span style=\"font-family: courier new,courier;\">std::vector<\/span> that is located on the stack instead of the heap. <span style=\"font-family: Courier New;\"><\/span><br \/> That is simple: We use a <span style=\"font-family: courier new,courier;\">std::array<\/span> or a C array.<span style=\"font-family: Courier New;\"><\/span><\/p>\n<p>But what does it look like if we want to have a<span style=\"font-family: courier new,courier;\"> std::set<\/span> on the stack?<\/p>\n<pre style=\"margin: 0px; line-height: 125%;\"><span style=\"color: #0000ff;\">#include &lt;set&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/container.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/memory_pool.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/namespace_alias.hpp&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;foonathan\/memory\/static_allocator.hpp&gt;<\/span>\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main()\r\n{\r\n    memory::static_allocator_storage&lt;4096u&gt; storage; <span style=\"color: #008000;\">\/\/ (1)<\/span>\r\n\r\n    <span style=\"color: #0000ff;\">using<\/span> static_pool = memory::memory_pool&lt;memory::node_pool, memory::static_allocator&gt;; <span style=\"color: #008000;\">\/\/ (2)<\/span>\r\n    static_pool pool(memory::set_node_size&lt;<span style=\"color: #2b91af;\">int<\/span>&gt;::value, 4096, storage); <span style=\"color: #008000;\">\/\/ (3)<\/span>\r\n\r\n    memory::set&lt;<span style=\"color: #2b91af;\">int<\/span>, decltype(pool)&gt; set(pool);\r\n    set.insert(3);\r\n    <span style=\"color: #008000;\">\/\/ ...<\/span>\r\n} \r\n\r\n<\/pre>\n<p>In this example, we combine the <span style=\"font-family: Courier New;\">memory_pool<\/span> with the <span style=\"font-family: Courier New;\">static_allocator<\/span> for the internal memory allocation. Like <span style=\"font-family: Courier New;\">heap_allocator<\/span>, you can use <span style=\"font-family: Courier New;\">static_allocator<\/span> as RawAllocator directly, but it makes more sense with a <span style=\"font-family: Courier New;\">memory_pool<\/span>. The allocators of <strong class=\"moz-txt-star\">memory<\/strong> are quite easy to combine to implement various strategies.<\/p>\n<p>At first, we create the memory which the static_allocator will use for its memory requests in (1). The alias in (2) defines our new pool type. <span style=\"font-family: Courier New;\">memory::memory_pool<\/span> has two template parameters. The first one is the type of pool, which you can adjust for different requirements. The default is <span style=\"font-family: Courier New;\">memory::node_pool<\/span>. The second parameter is the type of internal allocator. Here we use <span style=\"font-family: Courier New;\">memory::static_allocator<\/span>.&nbsp; We construct the pool in (3). This time we also have to give the <span style=\"font-family: Courier New;\">storage <\/span>needed by <span style=\"font-family: Courier New;\"><span style=\"font-family: Courier New;\">the memory::static_allocator.<\/span><\/span><\/p>\n<p>Now we can create our <span style=\"font-family: courier new,courier;\">set<\/span> that is located on the stack.<\/p>\n<p style=\"padding-left: 30px;\"> &nbsp;The internal allocator is a <span style=\"font-family: Courier New;\">BlockAllocator <\/span>and not a <span style=\"font-family: Courier New;\">RawAllocator<\/span> because you can directly control how big the blocks will become if the first block is out of memory. Template magic ensures you can give a RawAllocator, which automatically becomes a BlockAllocator.<\/p>\n<h3>Several pools<\/h3>\n<p>A memory_pool can only manage the memory of a specific size.<span style=\"font-family: Courier New;\"><\/span><br \/> If you need several sizes, you have to set the <strong class=\"moz-txt-star\">node size<\/strong> to its maximum and waste memory for smaller sizes, or you have to use several pools and choose the best fitting.<\/p>\n<p>The second alternative will be done in the <span style=\"font-family: Courier New;\">memory::memory_pool_collection<\/span> automatically.&nbsp; The class uses several pools and chooses the right one. It&#8217;s a template with three parameters. The first one is the type of pool, which is most of the time <span style=\"font-family: Courier New;\">memory::node_pool<\/span>. The second one is the distribution policy. These can be <span style=\"font-family: Courier New;\">memory::identity_buckets<\/span> &#8211; a pool of fixed size &#8211; or <span style=\"font-family: Courier New;\">memory::log2_buckets<\/span> &#8211; a pool for each power of two. The third one is &#8211; like in the regular pool &#8211; the allocator, which is used for internal memory.<\/p>\n<p>Please note that all pools share unused memory; each pool takes its share as needed.<\/p>\n<p> The usage is similar to the regular <span style=\"font-family: Courier New;\">memory_pool<\/span>. Therefore, I skip the example.<\/p>\n<p>Please note that the <strong class=\"moz-txt-star\">node size<\/strong> in the constructor is <strong class=\"moz-txt-star\">the maximum<\/strong> size and that the <span style=\"font-family: Courier New;\">allocate_node()<\/span> function needs a size.<br \/> Thanks to the <span style=\"font-family: Courier New;\">RawAllocator<\/span> is, the usage for STL containers, etc. identical.<\/p>\n<h3>Conclusion<\/h3>\n<p>There are a lot of libraries implementing pools. <strong class=\"moz-txt-star\">memory<\/strong> is the only one having all allocators for your needs. I did not present the whole functionality in this post. There are a lot more allocators and adapters. For example, a <span style=\"font-family: courier new,courier;\">Deleter<\/span> class for<span style=\"font-family: courier new,courier;\"> std::unique_ptr. <\/span>In addition, I didn&#8217;t mention the&nbsp; <span style=\"font-family: Courier New;\">allocator_storage<\/span> functionality implemented by <span style=\"font-family: Courier New;\">allocator_reference<\/span>.<\/p>\n<p>The library is designed so that you can put the allocator you need where you need it. But you can also fine-tune each detail if that&#8217;s required.<\/p>\n<p>If you want to know more about memory, watch my talk at <a href=\"http:\/\/%20foonathan.net\/meetingcpp2016\">Meeting C++.<\/a><\/p>\n<p>Of course, you can also follow me on Twitter or visit my <a href=\"https:\/\/foonathan.github.io\">blog.<\/a><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>This is my last post about embedded programming with C++ and memory management. The <a href=\"https:\/\/www.modernescpp.com\/index.php\/objectoriented-generic-and-functional-programming\">next post<\/a> will be about functional programming in C++.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p class=\"moz-signature\"><a href=\"https:\/\/www.modernescpp.com\/index.php\/blog\" class=\"moz-txt-link-freetext\"><\/a> <\/p>\n<p> <a href=\"https:\/\/github.com\/RainerGrimm\/ModernesCppSource\"><\/a><\/p>\n<p><span class=\"h3\"><\/span><\/p>\n<div>&nbsp;<\/div>\n<div>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>After I have written a few posts about memory management in C++, I&#8217;m very glad to present Jonathan M\u00fcller, which will write a guest post about his implementation of the memory library. He will explain to us his concepts about his design. Jonathan is known as an expert in memory management in the C++ community. [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":8269,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[364],"tags":[556,498,493],"class_list":["post-5117","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-embedded","tag-allocator","tag-memory","tag-new-delete"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5117","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5117"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5117\/revisions"}],"predecessor-version":[{"id":6899,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5117\/revisions\/6899"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/8269"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5117"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5117"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5117"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}