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