1 /** 2 * @copyright 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 * ==================================================================== 21 * @endcopyright 22 */ 23 24 #ifndef SVNXX_PRIVATE_APRWRAP_POOL_H 25 #define SVNXX_PRIVATE_APRWRAP_POOL_H 26 27 #include <cstdlib> 28 #include <functional> 29 #include <memory> 30 31 #include "svnxx/exception.hpp" 32 #include "svnxx/detail/noncopyable.hpp" 33 34 #include "../private/init_private.hpp" 35 36 #include "svn_pools.h" 37 38 namespace apache { 39 namespace subversion { 40 namespace svnxx { 41 namespace apr { 42 43 struct delete_pool 44 { operator ()apache::subversion::svnxx::apr::delete_pool45 void operator() (apr_pool_t* pool) 46 { 47 svn_pool_destroy(pool); 48 } 49 }; 50 51 using pool_ptr = std::unique_ptr<apr_pool_t, delete_pool>; 52 53 /** 54 * Encapsulates an APR pool. 55 */ 56 class pool : pool_ptr 57 { 58 friend class iteration; 59 struct iteration_proxy 60 { 61 pool& proxied_pool; 62 }; 63 64 static apr_pool_t* get_root_pool(); 65 66 struct allocation_size_overflowed final : public allocation_failed 67 { allocation_size_overflowedapache::subversion::svnxx::apr::pool::allocation_size_overflowed68 allocation_size_overflowed() noexcept 69 : allocation_failed("svn++ allocation size overflowed") 70 {} 71 }; 72 73 using allocator = std::function<void*(apr_pool_t*,apr_size_t)>; 74 template<typename T> safe_alloc(std::size_t count,allocator allocate)75 T* safe_alloc(std::size_t count, allocator allocate) 76 { 77 if (count > APR_SIZE_MAX / sizeof(T)) 78 throw allocation_size_overflowed(); 79 return static_cast<T*>(allocate(get(), count * sizeof(T))); 80 } 81 82 public: 83 /** 84 * Create a pool as a child of the application's root pool. 85 */ pool()86 pool() 87 : pool_ptr(svn_pool_create(get_root_pool())) 88 {} 89 90 /** 91 * Return a pool pointer that can be used by the C APIs. 92 */ get() const93 apr_pool_t* get() const noexcept 94 { 95 return pool_ptr::get(); 96 } 97 98 /** 99 * Create a pool as a child of @a parent. 100 */ pool(const pool * parent)101 explicit pool(const pool* parent) 102 : pool_ptr(svn_pool_create(parent->get())) 103 {} 104 105 /** 106 * Create a pool as a child of the global pool in @a state. 107 */ pool(const detail::global_state::ptr & state)108 explicit pool(const detail::global_state::ptr& state) 109 : pool_ptr(svn_pool_create(state->get_root_pool())) 110 {} 111 112 /** 113 * Clear the pool. 114 */ clear()115 void clear() 116 { 117 apr_pool_clear(get()); 118 } 119 120 /** 121 * Allocate space for @a count elements of type @a T from the pool. 122 * The contents of the allocated buffer will contain unspecified data. 123 */ 124 template<typename T> alloc(std::size_t count)125 T* alloc(std::size_t count) 126 { 127 // apr_palloc may be a macro, so wrap it in a closure. 128 static const auto palloc = [](apr_pool_t* p, apr_size_t size) 129 { 130 return apr_palloc(p, size); 131 }; 132 return safe_alloc<T>(count, palloc); 133 } 134 135 /** 136 * Allocate space for @a count elements of type @a T from the pool. 137 * The contents of the allocated buffer will be initialized to zero. 138 */ 139 template<typename T> allocz(std::size_t count)140 T* allocz(std::size_t count) 141 { 142 // apr_pcalloc may be a macro, so wrap it in a closure. 143 static const auto pcalloc = [](apr_pool_t* p, apr_size_t size) 144 { 145 return apr_pcalloc(p, size); 146 }; 147 return safe_alloc<T>(count, pcalloc); 148 } 149 operator iteration_proxy()150 operator iteration_proxy() noexcept 151 { 152 return iteration_proxy{*this}; 153 } 154 155 public: 156 /** 157 * Pool proxy used for iteration scratch pools. 158 * 159 * Construct this object inside a loop body in order to clear the 160 * proxied pool on every iteration. 161 */ 162 class iteration : detail::noncopyable 163 { 164 public: 165 /** 166 * The constructor clears the proxied pool. 167 */ iteration(pool::iteration_proxy iterbase)168 explicit iteration(pool::iteration_proxy iterbase) 169 : proxied(iterbase.proxied_pool) 170 { 171 proxied.clear(); 172 } 173 174 /** 175 * Returns a reference to the proxied pool. 176 */ get_pool() const177 apr::pool& get_pool() const noexcept 178 { 179 return proxied; 180 } 181 182 /** 183 * proxy method for pool::get() 184 */ get() const185 apr_pool_t* get() const noexcept 186 { 187 return proxied.get(); 188 } 189 190 /** 191 * Proxy method for pool::alloc() 192 */ 193 template<typename T> alloc(std::size_t count)194 T* alloc(std::size_t count) 195 { 196 return proxied.alloc<T>(count); 197 } 198 199 /** 200 * Proxy method for pool::allocz() 201 */ 202 template<typename T> allocz(std::size_t count)203 T* allocz(std::size_t count) 204 { 205 return proxied.allocz<T>(count); 206 } 207 208 private: 209 apr::pool& proxied; 210 }; 211 }; 212 213 } // namespace apr 214 } // namespace svnxx 215 } // namespace subversion 216 } // namespace apache 217 218 #endif // SVNXX_PRIVATE_APRWRAP_POOL_H 219