diff options
Diffstat (limited to 'subversion/bindings/cxx/src/aprwrap/pool.hpp')
-rw-r--r-- | subversion/bindings/cxx/src/aprwrap/pool.hpp | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/subversion/bindings/cxx/src/aprwrap/pool.hpp b/subversion/bindings/cxx/src/aprwrap/pool.hpp new file mode 100644 index 0000000..adb6c03 --- /dev/null +++ b/subversion/bindings/cxx/src/aprwrap/pool.hpp @@ -0,0 +1,218 @@ +/** + * @copyright + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * @endcopyright + */ + +#ifndef SVNXX_PRIVATE_APRWRAP_POOL_H +#define SVNXX_PRIVATE_APRWRAP_POOL_H + +#include <cstdlib> +#include <functional> +#include <memory> + +#include "svnxx/exception.hpp" +#include "svnxx/detail/noncopyable.hpp" + +#include "../private/init_private.hpp" + +#include "svn_pools.h" + +namespace apache { +namespace subversion { +namespace svnxx { +namespace apr { + +struct delete_pool +{ + void operator() (apr_pool_t* pool) + { + svn_pool_destroy(pool); + } +}; + +using pool_ptr = std::unique_ptr<apr_pool_t, delete_pool>; + +/** + * Encapsulates an APR pool. + */ +class pool : pool_ptr +{ + friend class iteration; + struct iteration_proxy + { + pool& proxied_pool; + }; + + static apr_pool_t* get_root_pool(); + + struct allocation_size_overflowed final : public allocation_failed + { + allocation_size_overflowed() noexcept + : allocation_failed("svn++ allocation size overflowed") + {} + }; + + using allocator = std::function<void*(apr_pool_t*,apr_size_t)>; + template<typename T> + T* safe_alloc(std::size_t count, allocator allocate) + { + if (count > APR_SIZE_MAX / sizeof(T)) + throw allocation_size_overflowed(); + return static_cast<T*>(allocate(get(), count * sizeof(T))); + } + +public: + /** + * Create a pool as a child of the application's root pool. + */ + pool() + : pool_ptr(svn_pool_create(get_root_pool())) + {} + + /** + * Return a pool pointer that can be used by the C APIs. + */ + apr_pool_t* get() const noexcept + { + return pool_ptr::get(); + } + + /** + * Create a pool as a child of @a parent. + */ + explicit pool(const pool* parent) + : pool_ptr(svn_pool_create(parent->get())) + {} + + /** + * Create a pool as a child of the global pool in @a state. + */ + explicit pool(const detail::global_state::ptr& state) + : pool_ptr(svn_pool_create(state->get_root_pool())) + {} + + /** + * Clear the pool. + */ + void clear() + { + apr_pool_clear(get()); + } + + /** + * Allocate space for @a count elements of type @a T from the pool. + * The contents of the allocated buffer will contain unspecified data. + */ + template<typename T> + T* alloc(std::size_t count) + { + // apr_palloc may be a macro, so wrap it in a closure. + static const auto palloc = [](apr_pool_t* p, apr_size_t size) + { + return apr_palloc(p, size); + }; + return safe_alloc<T>(count, palloc); + } + + /** + * Allocate space for @a count elements of type @a T from the pool. + * The contents of the allocated buffer will be initialized to zero. + */ + template<typename T> + T* allocz(std::size_t count) + { + // apr_pcalloc may be a macro, so wrap it in a closure. + static const auto pcalloc = [](apr_pool_t* p, apr_size_t size) + { + return apr_pcalloc(p, size); + }; + return safe_alloc<T>(count, pcalloc); + } + + operator iteration_proxy() noexcept + { + return iteration_proxy{*this}; + } + +public: + /** + * Pool proxy used for iteration scratch pools. + * + * Construct this object inside a loop body in order to clear the + * proxied pool on every iteration. + */ + class iteration : detail::noncopyable + { + public: + /** + * The constructor clears the proxied pool. + */ + explicit iteration(pool::iteration_proxy iterbase) + : proxied(iterbase.proxied_pool) + { + proxied.clear(); + } + + /** + * Returns a reference to the proxied pool. + */ + apr::pool& get_pool() const noexcept + { + return proxied; + } + + /** + * proxy method for pool::get() + */ + apr_pool_t* get() const noexcept + { + return proxied.get(); + } + + /** + * Proxy method for pool::alloc() + */ + template<typename T> + T* alloc(std::size_t count) + { + return proxied.alloc<T>(count); + } + + /** + * Proxy method for pool::allocz() + */ + template<typename T> + T* allocz(std::size_t count) + { + return proxied.allocz<T>(count); + } + + private: + apr::pool& proxied; + }; +}; + +} // namespace apr +} // namespace svnxx +} // namespace subversion +} // namespace apache + +#endif // SVNXX_PRIVATE_APRWRAP_POOL_H |