Boost.AFIO    Boost C++ Libraries
/home/jenkins-slave/workspace/Boost.AFIO Build Documentation/boost-local/libs/afio/include/boost/afio/v2/afio.hpp
Go to the documentation of this file.
00001 /* async_file_io
00002 Provides a threadpool and asynchronous file i/o infrastructure based on Boost.ASIO, Boost.Iostreams and filesystem
00003 (C) 2013-2015 Niall Douglas http://www.nedprod.com/
00004 File Created: Mar 2013
00005 
00006 
00007 Boost Software License - Version 1.0 - August 17th, 2003
00008 
00009 Permission is hereby granted, free of charge, to any person or organization
00010 obtaining a copy of the software and accompanying documentation covered by
00011 this license (the "Software") to use, reproduce, display, distribute,
00012 execute, and transmit the Software, and to prepare derivative works of the
00013 Software, and to permit third-parties to whom the Software is furnished to
00014 do so, all subject to the following:
00015 
00016 The copyright notices in the Software and this entire statement, including
00017 the above license grant, this restriction and the following disclaimer,
00018 must be included in all copies of the Software, in whole or in part, and
00019 all derivative works of the Software, unless such copies or derivative
00020 works are solely in the form of machine-executable object code generated by
00021 a source language processor.
00022 
00023 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00024 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00025 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
00026 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
00027 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
00028 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00029 DEALINGS IN THE SOFTWARE.
00030 */
00031 
00032 #ifndef BOOST_AFIO_HEADER_INCLUDED
00033 
00034 #ifdef DOXYGEN_SHOULD_SKIP_THIS
00035 #define BOOST_AFIO_HEADERS_ONLY 0
00036 #define BOOST_AFIO_USE_BOOST_THREAD 0
00037 #define BOOST_AFIO_USE_BOOST_FILESYSTEM 1
00038 #define ASIO_STANDALONE 0
00039 #endif
00040 
00041 #include "config.hpp"
00042 
00043 // clang-format off
00044 #ifdef DOXYGEN_SHOULD_SKIP_THIS
00045 #undef BOOST_AFIO_V2_NAMESPACE
00046 #undef BOOST_AFIO_V2_NAMESPACE_BEGIN
00047 #undef BOOST_AFIO_V2_NAMESPACE_END
00048 #undef BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC
00049 #undef BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC
00050 
00051 #define BOOST_AFIO_V2_NAMESPACE boost::afio
00052 #define BOOST_AFIO_V2_NAMESPACE_BEGIN namespace boost { namespace afio {
00053 #define BOOST_AFIO_V2_NAMESPACE_END } }
00054 #define BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC
00055 #define BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC virtual
00056 #endif
00057 // clang-format on
00058 
00059 #ifndef BOOST_AFIO_AFIO_H
00060 #define BOOST_AFIO_AFIO_H
00061 
00062 #include "detail/Undoer.hpp"
00063 #include "detail/ErrorHandling.hpp"
00064 #include "detail/Utility.hpp"
00065 #include <algorithm> // Boost.ASIO needs std::min and std::max
00066 #include <exception>
00067 #include <iostream>
00068 #include <type_traits>
00069 
00078 #ifndef BOOST_AFIO_VALIDATE_INPUTS
00079 #ifndef NDEBUG
00080 #define BOOST_AFIO_VALIDATE_INPUTS 1
00081 #else
00082 #define BOOST_AFIO_VALIDATE_INPUTS 0
00083 #endif
00084 #endif
00085 
00086 #ifdef BOOST_MSVC
00087 #pragma warning(push)
00088 #pragma warning(disable: 4251) // type needs to have dll-interface to be used by clients of class
00089 #endif
00090 
00107 BOOST_AFIO_V2_NAMESPACE_BEGIN
00108 
00109 // This isn't consistent on MSVC so hard code it
00110 typedef unsigned long long off_t;
00111 
00113 namespace detail
00114 {
00115     template<class R> class enqueued_task_impl
00116     {
00117     protected:
00118         struct Private
00119         {
00120             std::function<R()> task;
00121             promise<R> r;
00122             shared_future<R> f;
00123             bool autoset;
00124             atomic<int> done;
00125             Private(std::function<R()> _task) : task(std::move(_task)), f(r.get_future().share()), autoset(true), done(0) { }
00126         };
00127         std::shared_ptr<Private> p;
00128         void validate() const { assert(p); /*if(!p) abort();*/ }
00129     public:
00131         enqueued_task_impl(std::function<R()> _task=std::function<R()>()) : p(std::make_shared<Private>(std::move(_task))) { }
00133         bool valid() const noexcept{ return p.get()!=nullptr; }
00135         void swap(enqueued_task_impl &o) noexcept{ p.swap(o.p); }
00137         void reset() { p.reset(); }
00139         void set_task(std::function<R()> _task) { p->task=std::move(_task); }
00141         const shared_future<R> &get_future() const { validate(); return p->f; }
00143         template<class T> void set_future_value(T v)
00144         {
00145             int _=0;
00146             validate();
00147             if(!p->done.compare_exchange_strong(_, 1))
00148                 return;
00149             p->r.set_value(std::move(v));
00150         }
00151         void set_future_value()
00152         {
00153             int _=0;
00154             validate();
00155             if(!p->done.compare_exchange_strong(_, 1))
00156                 return;
00157             p->r.set_value();
00158         }
00160         void set_future_exception(exception_ptr e)
00161         {
00162             int _=0;
00163             validate();
00164             if(!p->done.compare_exchange_strong(_, 1))
00165                 return;
00166             p->r.set_exception(e);
00167         }
00169         void disable_auto_set_future(bool v=true) { validate(); p->autoset=!v; }
00170     };
00171 }
00172 
00173 template<class R> class enqueued_task;
00184 // Can't have args in callable type as that segfaults VS2010
00185 template<class R> class enqueued_task<R()> : public detail::enqueued_task_impl<R>
00186 {
00187     typedef detail::enqueued_task_impl<R> Base;
00188 public:
00190     enqueued_task(std::function<R()> _task=std::function<R()>()) : Base(std::move(_task)) { }
00192     void operator()()
00193     {
00194         auto _p(Base::p);
00195         Base::validate();
00196         if(!_p->task) abort();
00197         try
00198         {
00199             auto v(_p->task());
00200             if(_p->autoset && !_p->done) Base::set_future_value(v);
00201         }
00202         catch(...)
00203         {
00204             if(_p->done)
00205             {
00206               BOOST_AFIO_LOG_FATAL_EXIT(detail::output_exception_info << " thrown up to enqueued_task<> after stl_future set." << std::endl);
00207               BOOST_AFIO_THROW_FATAL(std::runtime_error("Exception thrown up to enqueued_task<> after stl_future set."));
00208             }
00209             if(_p->autoset && !_p->done) 
00210             {
00211                 auto e(current_exception());
00212                 Base::set_future_exception(e);
00213             }
00214         }
00215         // Free any bound parameters in task to save memory
00216         _p->task=std::function<R()>();
00217     }
00218 };
00219 template<> class enqueued_task<void()> : public detail::enqueued_task_impl<void>
00220 {
00221     typedef detail::enqueued_task_impl<void> Base;
00222 public:
00224     enqueued_task(std::function<void()> _task=std::function<void()>()) : Base(std::move(_task)) { }
00226     void operator()()
00227     {
00228         auto _p(Base::p);
00229         Base::validate();
00230         if(!_p->task) abort();
00231         try
00232         {
00233             _p->task();
00234             if(_p->autoset && !_p->done) Base::set_future_value();
00235         }
00236         catch(...)
00237         {
00238             if(_p->done)
00239             {
00240               BOOST_AFIO_LOG_FATAL_EXIT(detail::output_exception_info << " thrown up to enqueued_task<> after stl_future set." << std::endl);
00241               BOOST_AFIO_THROW_FATAL(std::runtime_error("Exception thrown up to enqueued_task<> after stl_future set."));
00242             }
00243             if(_p->autoset && !_p->done)
00244             {
00245                 auto e(current_exception());
00246                 Base::set_future_exception(e);
00247             }
00248         }
00249         // Free any bound parameters in task to save memory
00250         _p->task=std::function<void()>();
00251     }
00252 };
00260 class thread_source : public std::enable_shared_from_this<thread_source>
00261 {
00262 protected:
00263     asio::io_service &service;
00264     thread_source(asio::io_service &_service) : service(_service) { }
00265     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC ~thread_source() { }
00266     thread_source &operator=(const thread_source &) = delete;
00267 public:
00269     asio::io_service &io_service() { return service; }
00271     template<class R> void enqueue(enqueued_task<R> task)
00272     {
00273         service.post(task);
00274     }
00276     template<class F> shared_future<typename std::result_of<F()>::type> enqueue(F f)
00277     {
00278         typedef typename std::result_of<F()>::type R;
00279         enqueued_task<R()> out(std::move(f));
00280         auto ret(out.get_future());
00281         service.post(out);
00282         return ret;
00283     }
00284 };
00285 
00291 class std_thread_pool : public thread_source {
00292     class worker
00293     {
00294         std_thread_pool *pool;
00295     public:
00296         explicit worker(std_thread_pool *p) : pool(p) { }
00297         void operator()()
00298         {
00299             detail::set_threadname("boost::afio::std_thread_pool worker");
00300             try
00301             {
00302                 pool->service.run();
00303             }
00304             catch(...)
00305             {
00306               BOOST_AFIO_LOG_FATAL_EXIT("WARNING: ASIO exits via " << detail::output_exception_info << " which shouldn't happen." << std::endl);
00307             }
00308         }
00309     };
00310     friend class worker;
00311 
00312     asio::io_service service;
00313     std::unique_ptr<asio::io_service::work> working;
00314     std::vector< std::unique_ptr<thread> > workers;
00315 public:
00319     explicit std_thread_pool(size_t no) : thread_source(service), working(detail::make_unique<asio::io_service::work>(service))
00320     {
00321         add_workers(no);
00322     }
00324     void add_workers(size_t no)
00325     {
00326         workers.reserve(workers.size()+no);
00327         for(size_t n=0; n<no; n++)
00328             workers.push_back(detail::make_unique<thread>(worker(this)));
00329     }
00331     void destroy()
00332     {
00333         if(!service.stopped())
00334         {
00335             // Tell the threads there is no more work to do
00336             working.reset();
00337             for(auto &i: workers) { i->join(); }
00338             workers.clear();
00339             // For some reason ASIO occasionally thinks there is still more work to do
00340             if(!service.stopped())
00341                 service.run();
00342             service.stop();
00343             service.reset();
00344         }
00345     }
00346     ~std_thread_pool() final
00347     {
00348         destroy();
00349     }
00350 };
00356 BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC std::shared_ptr<std_thread_pool> process_threadpool();
00357 
00358 
00359 class dispatcher;
00360 using dispatcher_ptr = std::shared_ptr<dispatcher>;
00361 template<class T=void> class future;
00362 struct path_req;
00363 template<class T> struct io_req;
00364 struct enumerate_req;
00365 struct lock_req;
00366 namespace detail {
00367     struct async_io_handle_posix;
00368     struct async_io_handle_windows;
00369     struct dispatcher_p;
00370     class async_file_io_dispatcher_compat;
00371     class async_file_io_dispatcher_windows;
00372     class async_file_io_dispatcher_linux;
00373     class async_file_io_dispatcher_qnx;
00374     struct immediate_async_ops;
00375     template<bool for_writing> class io_req_impl;
00376 }
00377 
00379 enum class path_normalise
00380 {
00381   dos,         
00382   guid_volume, 
00383   guid_all     
00384 };
00385 
00397 class path : protected filesystem::path
00398 {
00399   void int_regularise()
00400   {
00401 #ifdef _MSC_VER
00402 #pragma warning(push)
00403 #pragma warning(disable: 6326) // comparison of constants
00404 #endif
00405     if(preferred_separator!='/')
00406       make_preferred();
00407 #ifdef _MSC_VER
00408 #pragma warning(pop)
00409 #endif
00410 #ifdef WIN32
00411     // Need to strip off any win32 prefixing, and instead prefix any drive letters
00412     bool isExtendedPath=false, isDevicePath=false;
00413     if(native().size()>=4)
00414     {
00415 #ifndef NDEBUG
00416       if(native()[0]=='\\' && native()[1]=='?' && native()[2]=='?' && native()[3]=='\\')
00417       {
00418         assert(!(native()[0]=='\\' && native()[1]=='?' && native()[2]=='?' && native()[3]=='\\'));
00419       }
00420 #endif
00421       isExtendedPath=(native()[0]=='\\' && native()[1]=='\\' && native()[2]=='?' && native()[3]=='\\');
00422       isDevicePath=(native()[0]=='\\' && native()[1]=='\\' && native()[2]=='.' && native()[3]=='\\');
00423     }
00424     bool hasDriveLetter=(isalpha(native()[((int) isExtendedPath+(int) isDevicePath)*4+0]) && native()[((int) isExtendedPath+(int) isDevicePath)*4+1]==':');
00425     if(hasDriveLetter && (isExtendedPath || isDevicePath))
00426     {
00427       filesystem::path::string_type &me=const_cast<filesystem::path::string_type &>(native());
00428       me[1]=me[2]='?';
00429     }
00430     else if(hasDriveLetter)
00431     {
00432       filesystem::path::string_type &me=const_cast<filesystem::path::string_type &>(native());
00433       me=L"\\??\\"+me;
00434     }
00435     else if(isExtendedPath || isDevicePath)
00436     {
00437       filesystem::path::string_type &me=const_cast<filesystem::path::string_type &>(native());
00438       me=me.substr(isDevicePath ? 3 : 4);
00439     }
00440 #endif
00441   }
00442   friend struct detail::async_io_handle_windows;
00443   struct direct { };
00444   path(filesystem::path &&p, direct) : filesystem::path(std::move(p)) { }
00445 public:
00446   typedef filesystem::path::value_type value_type;
00447   typedef filesystem::path::string_type string_type;
00448   using filesystem::path::preferred_separator;
00450   struct make_absolute;
00451 
00453   path() {}
00455   path(const path &p) : filesystem::path(p) { }
00457   path(const filesystem::path &p) : filesystem::path(p) { int_regularise(); }
00459   path(const char *p) : filesystem::path(p) { int_regularise(); }
00460 #ifdef WIN32
00461 
00462   path(const wchar_t *p) : filesystem::path(p) { int_regularise(); }
00464   path(const std::string &p) : filesystem::path(p) { int_regularise(); }
00465 #endif
00466 
00467   path(const string_type &p) : filesystem::path(p) { int_regularise(); }
00469   path(path &&p) noexcept : filesystem::path(std::move(p)) { }
00471   path(filesystem::path &&p) : filesystem::path(std::move(p)) { int_regularise(); }
00472 #ifdef WIN32
00473 
00474   path(std::string &&p) : filesystem::path(std::move(p)) { int_regularise(); }
00475 #endif
00476 
00477   path(string_type &&p) : filesystem::path(std::move(p)) { int_regularise(); }
00479   //template<class Source> path(const Source &source) : filesystem::path(source) { int_regularise(); }
00481   template <class InputIterator> path(InputIterator begin, InputIterator end) : filesystem::path(begin, end) { int_regularise(); }
00483   path& operator=(const path& p) { filesystem::path::operator=(filesystem::path(p)); return *this; }
00485   path& operator=(path&& p) noexcept { filesystem::path::operator=(static_cast<filesystem::path &&>(p)); return *this; }
00487   //template <class Source> path& operator=(Source const& source) { filesystem::path::operator=(source); int_regularise(); return *this; }
00488 
00489   template <class Source>
00490     path& assign(Source const& source) { filesystem::path::assign(source); return *this; }
00491   template <class InputIterator>
00492     path& assign(InputIterator begin, InputIterator end) { filesystem::path::assign(begin, end); return *this; }
00493   path& operator/=(const path& p) { filesystem::path::operator/=(filesystem::path(p)); return *this; }
00494   template <class Source>
00495     path& operator/=(Source const& source) { filesystem::path::operator/=(source); return *this; }
00496   template <class Source>
00497     path& append(Source const& source) { filesystem::path::append(source); return *this; }
00498   template <class InputIterator>
00499     path& append(InputIterator begin, InputIterator end) { filesystem::path::append(begin, end); return *this; }
00500 
00501   path& operator+=(const path& x) { filesystem::path::operator+=(filesystem::path(x)); return *this; }
00502   path& operator+=(const string_type& x) { filesystem::path::operator+=(x); return *this; }
00503   path& operator+=(const value_type* x) { filesystem::path::operator+=(x); return *this; }
00504   path& operator+=(value_type x) { filesystem::path::operator+=(x); return *this; }
00505   template <class Source>
00506     path& operator+=(Source const& x) { filesystem::path::operator+=(x); return *this; }
00507   template <class Source>
00508     path& concat(Source const& x) { filesystem::path::concat(x); return *this; }
00509   template <class InputIterator>
00510     path& concat(InputIterator begin, InputIterator end) { filesystem::path::concat(begin, end); return *this; }
00511   
00512   using filesystem::path::clear;
00513   path& make_preferred() { filesystem::path::make_preferred(); return *this; }
00514   path& remove_filename() { filesystem::path::remove_filename(); return *this; }
00515   path& replace_extension(const path& new_extension = path()) { filesystem::path::replace_extension(filesystem::path(new_extension)); return *this; }
00516   using filesystem::path::swap;
00517 
00518   using filesystem::path::native;
00519   using filesystem::path::c_str;
00520   using filesystem::path::string;
00521   using filesystem::path::wstring;
00522   using filesystem::path::generic_string;
00523   using filesystem::path::compare;
00524 
00525   path  root_name() const { return path(filesystem::path::root_name(), direct()); }
00526   path  root_directory() const { return path(filesystem::path::root_directory(), direct()); }
00527   path  root_path() const { return path(filesystem::path::root_path(), direct()); }
00528   path  relative_path() const { return path(filesystem::path::relative_path(), direct()); }
00529   path  parent_path() const { return path(filesystem::path::parent_path(), direct()); }
00530 #ifdef BOOST_AFIO_USE_LEGACY_FILESYSTEM_SEMANTICS
00531   path  filename() const { return path(filesystem::path::leaf(), direct()); }
00532 #else
00533   path  filename() const { return path(filesystem::path::filename(), direct()); }
00534 #endif
00535   path  stem() const { return path(filesystem::path::stem(), direct()); }
00536   path  extension() const { return path(filesystem::path::extension(), direct()); }
00537 
00538   using filesystem::path::empty;
00539   using filesystem::path::has_root_name;
00540   using filesystem::path::has_root_directory;
00541   using filesystem::path::has_root_path;
00542   using filesystem::path::has_relative_path;
00543   using filesystem::path::has_parent_path;
00544   using filesystem::path::has_filename;
00545   using filesystem::path::has_stem;
00546   using filesystem::path::has_extension;
00547   using filesystem::path::is_absolute;
00548   using filesystem::path::is_relative;
00549 
00550   // TODO FIXME: Need our own iterator here
00551   typedef filesystem::path::iterator iterator;
00552   typedef filesystem::path::const_iterator const_iterator;
00553 
00554   iterator begin() const { return filesystem::path::begin(); }
00555   iterator end() const { return filesystem::path::end(); }
00556   
00568   filesystem::path filesystem_path() const
00569   {
00570 #ifdef WIN32
00571     bool isSymlinkedDosPath=(native()[0]=='\\' && native()[1]=='?' && native()[2]=='?' && native()[3]=='\\');
00572     if(isSymlinkedDosPath)
00573     {
00574       filesystem::path::string_type p(native());
00575       p[1]='\\';
00576       return p;
00577     }
00578     else
00579       return filesystem::path(L"\\\\.")/filesystem::path(*this);
00580 #else
00581     return *this;
00582 #endif
00583   }
00584   friend inline bool operator<(const path& lhs, const path& rhs);
00585   friend inline bool operator<=(const path& lhs, const path& rhs);
00586   friend inline bool operator>(const path& lhs, const path& rhs);
00587   friend inline bool operator>=(const path& lhs, const path& rhs);
00588   friend inline bool operator==(const path& lhs, const path& rhs);
00589   friend inline bool operator!=(const path& lhs, const path& rhs);
00590   friend inline path operator/(const path& lhs, const path& rhs);
00591   friend inline std::ostream &operator<<(std::ostream &s, const path &p);
00592   friend struct path_hash;
00593 #ifdef WIN32
00594 #ifdef _MSC_VER
00595   friend BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC filesystem::path normalise_path(path p, path_normalise type);
00596 #else
00597   friend filesystem::path normalise_path(path p, path_normalise type);
00598 #endif
00599 #else
00600   friend inline filesystem::path normalise_path(path p, path_normalise type);
00601 #endif
00602 };
00603 inline bool operator<(const path& lhs, const path& rhs) { return filesystem::path(lhs)<filesystem::path(rhs); }
00604 inline bool operator<=(const path& lhs, const path& rhs) { return filesystem::path(lhs)<=filesystem::path(rhs); }
00605 inline bool operator>(const path& lhs, const path& rhs) { return filesystem::path(lhs)>filesystem::path(rhs); }
00606 inline bool operator>=(const path& lhs, const path& rhs) { return filesystem::path(lhs)>=filesystem::path(rhs); }
00607 inline bool operator==(const path& lhs, const path& rhs) { return filesystem::path(lhs)==filesystem::path(rhs); }
00608 inline bool operator!=(const path& lhs, const path& rhs) { return filesystem::path(lhs)!=filesystem::path(rhs); }
00609 inline path operator/(const path& lhs, const path& rhs) { return path(filesystem::path(lhs)/filesystem::path(rhs), path::direct()); }
00610 inline std::ostream &operator<<(std::ostream &s, const path &p) { return s << filesystem::path(p); }
00612 struct path::make_absolute : public path
00613 {
00614   make_absolute(const path &p) : path(p)
00615   {
00616     if(native()[0]!=preferred_separator)
00617       *this=filesystem::absolute(std::move(*this));
00618   }
00619   make_absolute(path &&p) : path(std::move(p))
00620   {
00621     if(native()[0]!=preferred_separator)
00622       *this=filesystem::absolute(std::move(*this));
00623   }
00624   template<class T, typename=typename std::enable_if<std::is_constructible<filesystem::path, T>::value>::type> make_absolute(T &&p) : path(filesystem::absolute(std::forward<T>(p))) { }
00625 };
00628 struct path_hash
00629 {
00630   std::hash<path::string_type> hasher;
00631 public:
00632     size_t operator()(const path &p) const
00633     {
00634       return hasher(p.native());
00635     }
00636 };
00637 
00654 #ifdef WIN32
00655 BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC filesystem::path normalise_path(path p, path_normalise type=path_normalise::dos);
00656 #else
00657 inline filesystem::path normalise_path(path p, path_normalise type=path_normalise::dos) { return p; }
00658 #endif
00659 
00660 
00661 #define BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(type) \
00662 inline constexpr type operator&(type a, type b) \
00663 { \
00664     return static_cast<type>(static_cast<size_t>(a) & static_cast<size_t>(b)); \
00665 } \
00666 inline constexpr type operator|(type a, type b) \
00667 { \
00668     return static_cast<type>(static_cast<size_t>(a) | static_cast<size_t>(b)); \
00669 } \
00670 inline constexpr type operator~(type a) \
00671 { \
00672     return static_cast<type>(~static_cast<size_t>(a)); \
00673 } \
00674 inline constexpr bool operator!(type a) \
00675 { \
00676     return 0==static_cast<size_t>(a); \
00677 }
00678 
00679 
00680 
00685 enum class file_flags : size_t
00686 {
00687     none=0,             
00688     read=1,             
00689     write=2,            
00690     read_write=3,       
00691     append=4,           
00692     truncate=8,         
00693     create=16,          
00694     create_only_if_not_exist=32, 
00695     create_compressed=64, 
00696 
00697     will_be_sequentially_accessed=128, 
00698     will_be_randomly_accessed=256, 
00699     no_sparse=512,      
00700 
00701     hold_parent_open=(1<<10),        
00702     unique_directory_handle=(1<<11), 
00703     no_race_protection=(1<<12),      
00704     temporary_file=(1<<13),          
00705     delete_on_close=(1<<14),         
00706 
00707     os_direct=(1<<16),      
00708     os_lockable=(1<<17),    // Deliberately undocumented
00709 
00710     always_sync=(1<<24),    
00711     sync_on_close=(1<<25),  
00712 
00713     int_hold_parent_open_nested=(1<<27), 
00714     int_file_share_delete=(1<<28), 
00715     int_opening_link=(1<<29), 
00716     int_opening_dir=(1<<30) 
00717 };
00718 BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(file_flags)
00719 
00720 
00724 enum class async_op_flags : size_t
00725 {
00726     none=0,                 
00727     immediate=1             
00728 };
00729 BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(async_op_flags)
00730 
00731 namespace detail {
00735     enum class OpType
00736     {
00737         Unknown,
00738         UserCompletion,
00739         dir,
00740         rmdir,
00741         file,
00742         rmfile,
00743         symlink,
00744         rmsymlink,
00745         sync,
00746         close,
00747         read,
00748         write,
00749         truncate,
00750         barrier,
00751         enumerate,
00752         adopt,
00753         zero,
00754         extents,
00755         statfs,
00756         lock,
00757 
00758         Last
00759     };
00760     static const char *optypes[]={
00761         "unknown",
00762         "UserCompletion",
00763         "dir",
00764         "rmdir",
00765         "file",
00766         "rmfile",
00767         "symlink",
00768         "rmsymlink",
00769         "sync",
00770         "close",
00771         "read",
00772         "write",
00773         "truncate",
00774         "barrier",
00775         "enumerate",
00776         "adopt",
00777         "zero",
00778         "extents",
00779         "statfs",
00780         "lock"
00781     };
00782     static_assert(static_cast<size_t>(OpType::Last)==sizeof(optypes)/sizeof(*optypes), "You forgot to fix up the strings matching OpType");
00783 
00784     enum class unit_testing_flags : size_t
00785     {
00786         none=0,                  
00787         no_symbol_lookup=(1<<0)  
00788     };
00789     BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(unit_testing_flags)
00790 }
00791 
00792 class handle;
00794 using handle_ptr = std::shared_ptr<handle>;
00795 
00802 enum class metadata_flags : size_t
00803 {
00804     None=0,
00805     dev=1<<0,
00806     ino=1<<1,
00807     type=1<<2,
00808     perms=1<<3,
00809     nlink=1<<4,
00810     uid=1<<5,
00811     gid=1<<6,
00812     rdev=1<<7,
00813     atim=1<<8,
00814     mtim=1<<9,
00815     ctim=1<<10,
00816     size=1<<11,
00817     allocated=1<<12,
00818     blocks=1<<13,
00819     blksize=1<<14,
00820     flags=1<<15,
00821     gen=1<<16,
00822     birthtim=1<<17,
00823     sparse=1<<24,
00824     compressed=1<<25,
00825     reparse_point=1<<26,
00826     All=(size_t)-1       
00827 };
00828 BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(metadata_flags)
00850 struct stat_t
00851 {
00852 #ifndef WIN32
00853     uint64_t        st_dev;                       
00854 #endif
00855     uint64_t        st_ino;                       
00856     filesystem::file_type st_type;                
00857 #ifndef WIN32
00858 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00859     uint16_t        st_perms;
00860 #else
00861     filesystem::perms st_perms;                   
00862 #endif
00863 #endif
00864     int16_t         st_nlink;                     
00865 #ifndef WIN32
00866     int16_t         st_uid;                       
00867     int16_t         st_gid;                       
00868     dev_t           st_rdev;                      
00869 #endif
00870     chrono::system_clock::time_point st_atim;     
00871     chrono::system_clock::time_point st_mtim;     
00872     chrono::system_clock::time_point st_ctim;     
00873     off_t           st_size;                      
00874     off_t           st_allocated;                 
00875     off_t           st_blocks;                    
00876     uint16_t        st_blksize;                   
00877     uint32_t        st_flags;                     
00878     uint32_t        st_gen;                       
00879     chrono::system_clock::time_point st_birthtim; 
00881     unsigned        st_sparse : 1;                
00882     unsigned        st_compressed : 1;            
00883     unsigned        st_reparse_point : 1;         
00885 
00886     stat_t() { }
00888     stat_t(std::nullptr_t) :
00889 #ifndef WIN32
00890         st_dev(0),
00891 #endif
00892         st_ino(0),
00893 #ifdef BOOST_AFIO_USE_LEGACY_FILESYSTEM_SEMANTICS
00894         st_type(filesystem::file_type::type_unknown),
00895 #else
00896         st_type(filesystem::file_type::unknown),
00897 #endif
00898 #ifndef WIN32
00899         st_perms(0),
00900 #endif
00901         st_nlink(0),
00902 #ifndef WIN32
00903         st_uid(0), st_gid(0), st_rdev(0),
00904 #endif
00905         st_size(0), st_allocated(0), st_blocks(0), st_blksize(0), st_flags(0), st_gen(0), st_sparse(0), st_compressed(0), st_reparse_point(0) { }
00906 };
00907 
00912 enum class fs_metadata_flags : size_t
00913 {
00914     None=0,
00915     flags=1<<1,
00916     bsize=1<<2,
00917     iosize=1<<3,
00918     blocks=1<<4,
00919     bfree=1<<5,
00920     bavail=1<<6,
00921     files=1<<7,
00922     ffree=1<<8,
00923     namemax=1<<9,
00924     owner=1<<10,
00925     fsid=1<<11,
00926     fstypename=1<<12,
00927     mntfromname=1<<13,
00928     mntonname=1<<14,
00929     All=(size_t)-1       
00930 };
00931 BOOST_AFIO_DECLARE_CLASS_ENUM_AS_BITFIELD(fs_metadata_flags)
00939 struct statfs_t
00940 {
00941      struct f_flags_t
00942      {
00943         uint32_t rdonly : 1;          
00944         uint32_t noexec : 1;          
00945         uint32_t nosuid : 1;          
00946         uint32_t acls : 1;            
00947         uint32_t xattr : 1;           
00948         uint32_t compression : 1;     
00949         uint32_t extents : 1;         
00950         uint32_t filecompression : 1; 
00951      } f_flags;                           
00952      uint64_t f_bsize;                    
00953      uint64_t f_iosize;                   
00954      uint64_t f_blocks;                   
00955      uint64_t f_bfree;                    
00956      uint64_t f_bavail;                   
00957      uint64_t f_files;                    
00958      uint64_t f_ffree;                    
00959      uint32_t f_namemax;                  
00960 #ifndef WIN32
00961      int16_t  f_owner;                    
00962 #endif
00963      uint64_t f_fsid[2];                  
00964      std::string f_fstypename;            
00965      std::string f_mntfromname;           
00966      path f_mntonname;        
00967      statfs_t()
00968      {
00969        size_t frontbytes=((char *) &f_fstypename)-((char *) this);
00970        memset(this, 0xff, frontbytes);
00971        memset(this, 0, sizeof(f_flags));
00972      }
00973 };
00974 
00986 class BOOST_AFIO_DECL directory_entry
00987 {
00988     friend class detail::async_file_io_dispatcher_compat;
00989     friend class detail::async_file_io_dispatcher_windows;
00990     friend class detail::async_file_io_dispatcher_linux;
00991     friend class detail::async_file_io_dispatcher_qnx;
00992 
00993     path::string_type leafname;
00994     stat_t stat;
00995     metadata_flags have_metadata;
00996     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void _int_fetch(metadata_flags wanted, handle_ptr dirh);
00997 public:
00999     directory_entry() : stat(nullptr), have_metadata(metadata_flags::None) { }
01001     directory_entry(path::string_type _leafname, stat_t __stat, metadata_flags _have_metadata) : leafname(_leafname), stat(__stat), have_metadata(_have_metadata) { }
01002     directory_entry(const directory_entry &) = default;
01003     directory_entry &operator=(const directory_entry &) = default;
01004     directory_entry(directory_entry &&o) noexcept : leafname(std::move(o.leafname)), stat(std::move(o.stat)), have_metadata(std::move(o.have_metadata)) { }
01005     directory_entry &operator=(directory_entry &&o) noexcept
01006     {
01007         leafname=std::move(o.leafname);
01008         stat=std::move(o.stat);
01009         have_metadata=std::move(o.have_metadata);
01010         return *this;
01011     }
01012 
01013     bool operator==(const directory_entry& rhs) const noexcept { return leafname == rhs.leafname; }
01014     bool operator!=(const directory_entry& rhs) const noexcept { return leafname != rhs.leafname; }
01015     bool operator< (const directory_entry& rhs) const noexcept { return leafname < rhs.leafname; }
01016     bool operator<=(const directory_entry& rhs) const noexcept { return leafname <= rhs.leafname; }
01017     bool operator> (const directory_entry& rhs) const noexcept { return leafname > rhs.leafname; }
01018     bool operator>=(const directory_entry& rhs) const noexcept { return leafname >= rhs.leafname; }
01020     path::string_type name() const noexcept { return leafname; }
01022     metadata_flags metadata_ready() const noexcept { return have_metadata; }
01029     metadata_flags fetch_metadata(handle_ptr dirh, metadata_flags wanted)
01030     {
01031         metadata_flags tofetch;
01032         wanted=wanted&metadata_supported();
01033         tofetch=wanted&~have_metadata;
01034         if(!!tofetch) _int_fetch(tofetch, dirh);
01035         return have_metadata;
01036     }
01043     stat_t fetch_lstat(handle_ptr dirh, metadata_flags wanted=directory_entry::metadata_fastpath())
01044     {
01045         fetch_metadata(dirh, wanted);
01046         return stat;
01047     }
01048 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01049 #define BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(field) \
01050 decltype(stat_t().st_##field) st_##field() const { if(!(have_metadata&metadata_flags::field)) { BOOST_AFIO_THROW(std::runtime_error("Field st_" #field " not present.")); } return stat.st_##field; } \
01051 decltype(stat_t().st_##field) st_##field(handle_ptr dirh) { if(!(have_metadata&metadata_flags::field)) { _int_fetch(metadata_flags::field, dirh); } return stat.st_##field; }
01052 #else
01053 #define BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(field) \
01054 fieldtype st_##field(handle_ptr dirh=handle_ptr()) { if(!(have_metadata&metadata_flags::field)) { _int_fetch(metadata_flags::field, dirh); } return stat.st_##field; }
01055 #endif
01056 #ifndef WIN32
01057 
01058     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(dev)
01059 #endif
01060 
01061     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(ino)
01063     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(type)
01064 #ifndef WIN32
01065 
01066     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(perms)
01067 #endif
01068 
01069     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(nlink)
01070 #ifndef WIN32
01071 
01072     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(uid)
01074     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(gid)
01076     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(rdev)
01077 #endif
01078 
01079     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(atim)
01081     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(mtim)
01083     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(ctim)
01085     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(size)
01087     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(allocated)
01089     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(blocks)
01091     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(blksize)
01093     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(flags)
01095     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(gen)
01097     BOOST_AFIO_DIRECTORY_ENTRY_ACCESS_METHOD(birthtim)
01098 
01100     static BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC metadata_flags metadata_supported() noexcept;
01102     static BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC metadata_flags metadata_fastpath() noexcept;
01104     static BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC size_t compatibility_maximum() noexcept;
01105 };
01106 
01109 struct directory_entry_hash
01110 {
01111 public:
01112 #ifdef _MSC_VER
01113 #pragma warning(push)
01114 #pragma warning(disable: 4310) // cast truncates constant value
01115 #endif
01116     size_t operator()(const directory_entry &p) const
01117     {
01118         size_t seed = (size_t) 0x9ddfea08eb382d69ULL;
01119         detail::hash_combine(seed, p.st_ino());
01120         if(!!(directory_entry::metadata_supported() & metadata_flags::birthtim))
01121             detail::hash_combine(seed, p.st_birthtim().time_since_epoch().count());
01122         return seed;
01123     }
01124 #ifdef _MSC_VER
01125 #pragma warning(pop)
01126 #endif
01127 };
01128 
01139 class handle : public std::enable_shared_from_this<handle>
01140 {
01141     friend class dispatcher;
01142     friend struct detail::async_io_handle_posix;
01143     friend struct detail::async_io_handle_windows;
01144     friend class detail::async_file_io_dispatcher_compat;
01145     friend class detail::async_file_io_dispatcher_windows;
01146     friend class detail::async_file_io_dispatcher_linux;
01147     friend class detail::async_file_io_dispatcher_qnx;
01148 
01149     dispatcher *_parent;
01150     chrono::system_clock::time_point _opened;
01151     file_flags _flags;
01152 protected:
01153     handle_ptr dirh;
01154     atomic<off_t> bytesread, byteswritten, byteswrittenatlastfsync;
01155     handle(dispatcher *parent, file_flags flags) : _parent(parent), _opened(chrono::system_clock::now()), _flags(flags), bytesread(0), byteswritten(0), byteswrittenatlastfsync(0) { }
01157     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void close() BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01158 public:
01159     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC ~handle() { }
01161     dispatcher *parent() const { return _parent; }
01163     handle_ptr container() const { return dirh; }
01165     enum class open_states
01166     {
01167       closed, 
01168       open,   
01169       opendir 
01170     };
01172     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC open_states is_open() const BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01174     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void *native_handle() const BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01176     const chrono::system_clock::time_point &opened() const { return _opened; }
01192     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC BOOST_AFIO_V2_NAMESPACE::path path(bool refresh=false) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01194     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC BOOST_AFIO_V2_NAMESPACE::path path() const BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01196     file_flags flags() const { return _flags; }
01198     bool opened_as_file() const { return !(_flags&file_flags::int_opening_dir) && !(_flags&file_flags::int_opening_link); }
01200     bool opened_as_dir() const { return !!(_flags&file_flags::int_opening_dir); }
01202     bool opened_as_symlink() const { return !!(_flags&file_flags::int_opening_link); }
01204     bool available_to_directory_cache() const { return opened_as_dir() && !(_flags&file_flags::unique_directory_handle) && !!(_flags&file_flags::read) && !(_flags&file_flags::write); }
01206     off_t read_count() const { return bytesread; }
01208     off_t write_count() const { return byteswritten; }
01210     off_t write_count_since_fsync() const { return byteswritten-byteswrittenatlastfsync; }
01224     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC directory_entry direntry(metadata_flags wanted=directory_entry::metadata_fastpath()) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01229     stat_t lstat(metadata_flags wanted=directory_entry::metadata_fastpath())
01230     {
01231         directory_entry de(direntry(wanted));
01232         return de.fetch_lstat(handle_ptr() /* actually unneeded */, wanted);
01233     }
01245     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC BOOST_AFIO_V2_NAMESPACE::path target() BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01247     struct BOOST_AFIO_DECL mapped_file
01248     {
01249       friend class handle;
01250       handle_ptr h;   
01251       void *addr;     
01252       size_t length;  
01253       off_t offset;   
01254       mapped_file(const mapped_file &) = delete;
01255       mapped_file(mapped_file &&) = delete;
01256       mapped_file &operator=(const mapped_file &) = delete;
01257       mapped_file &operator=(mapped_file &&) = delete;
01258       mapped_file(handle_ptr _h, void *_addr, size_t _length, off_t _offset) : h(std::move(_h)), addr(_addr), length(_length), offset(_offset) { }
01259       ~mapped_file();
01260     };
01262     using mapped_file_ptr = std::unique_ptr<mapped_file>;
01264     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC mapped_file_ptr map_file(size_t length = (size_t)-1, off_t offset = 0, bool read_only = false) { return nullptr; }
01286     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void link(const path_req &req) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01321     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void unlink() BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01348     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void atomic_relink(const path_req &req) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01349 
01350 #if 0
01351     // Undocumented deliberately
01352     enum class change_flags : size_t
01353     {
01354       created=(1<<0),    // NOTE_EXTEND,                       IN_CREATE, 
01355       renamed=(1<<1),    // NOTE_RENAME,       IN_MOVED_FROM/IN_MOVED_TO, 
01356       deleted=(1<<2),    // NOTE_DELETE,                       IN_DELETE, 
01357       attributes=(1<<3), // NOTE_ATTRIB,                       IN_ATTRIB, 
01358       opened=(1<<4),     //           ?,                         IN_OPEN, 
01359       closed=(1<<5),     //           ?, IN_CLOSE_WRITE/IN_CLOSE_NOWRITE, 
01360       read=(1<<6),       //           ?,                       IN_ACCESS, 
01361       written=(1<<7),    //  NOTE_WRITE,                       IN_MODIFY, 
01362       extended=(1<<8),   // NOTE_EXTEND,                               ?, 
01363       
01364       region_locked=(1<<16),
01365       region_timedout=(1<<17),
01366       region_unlocked=(1<<18)
01367     };
01368     // Undocumented deliberately
01369     struct change_listener : public std::enable_shared_from_this<change_listener>
01370     {
01371       virtual ~change_listener() { }
01372       virtual void operator()(handle *h, change_flags changed, void *additional)=0;
01373     };
01374     // Undocumented deliberately
01375     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void listen(const std::vector<std::pair<change_flags>, std::shared_ptr<change_listener>> &listeners) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01376     // Undocumented deliberately
01377     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC void unlisten(const std::vector<std::pair<change_flags>, std::shared_ptr<change_listener>> &listeners) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
01378 #endif
01379 };
01380 
01388 BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC dispatcher_ptr current_dispatcher(option<dispatcher_ptr> new_dispatcher = empty);
01389 
01396 class current_dispatcher_guard
01397 {
01398   dispatcher_ptr _old;
01399 public:
01400   current_dispatcher_guard(dispatcher_ptr _new) : _old(current_dispatcher(_new)) { }
01401   ~current_dispatcher_guard() { current_dispatcher(_old); }
01403   void release() { current_dispatcher(_old); _old.reset(); }
01405   void dismiss() { _old.reset(); }
01407   void reset(dispatcher_ptr p) { _old=p; }
01408 };
01409 
01411 template<class T> struct is_future : std::false_type { };
01412 template<class T> struct is_future<future<T>> : std::true_type {};
01413 
01414 // Temporary friends for future<>
01415 namespace detail
01416 {
01417   struct barrier_count_completed_state;
01418   template<bool rethrow, class Iterator> inline stl_future<std::vector<handle_ptr>> when_all_ops(Iterator first, Iterator last);
01419   template<bool rethrow, class Iterator> inline stl_future<handle_ptr> when_any_ops(Iterator first, Iterator last);
01420 
01421   // Shim code for lightweight future continuations
01422   template<class R, bool return_is_lightweight_future=is_lightweight_future<R>::value, bool return_is_afio_future=is_future<R>::value> struct continuation_return_type { using future_type = future<R>; using promise_type = void; };
01423   template<class R, bool _> struct continuation_return_type<R, true, _> { using future_type = R; using promise_type = typename future_type::promise_type; };
01424   template<class R, bool _> struct continuation_return_type<R, _, true> { using future_type = R; using promise_type = void; };
01425   template<class future_type, class promise_type> struct do_continuation;
01426 }
01427 
01430 template<> class future<void>
01431 {
01432     // Temporary friends until lightweight future promise comes in
01433     friend struct detail::barrier_count_completed_state;
01434     template<bool rethrow, class Iterator> friend inline stl_future<std::vector<handle_ptr>> detail::when_all_ops(Iterator first, Iterator last);
01435     template<bool rethrow, class Iterator> friend inline stl_future<handle_ptr> detail::when_any_ops(Iterator first, Iterator last);
01436 
01437     dispatcher *_parent;              
01438     size_t _id;                                          
01439     shared_future<handle_ptr> _h;  
01440 public:
01441     future(future<void> &&o, stl_future<void> &&result) : future<void>(std::move(o)) { }
01442     // NOTE TO SELF: MAKE THE CONSTRUCTORS AND MEMBER FUNCTIONS constexpr WHEN I MERGE LIGHTWEIGHT FUTURE-PROMISES
01443 
01445     using value_type = void;
01447     using error_type = error_code;
01449     using exception_type = exception_ptr;
01450 
01452     future() : _parent(nullptr), _id(0) { }
01454     future(const future &o) = default;
01456     future(future &&o) = default;
01464     future(dispatcher *parent, size_t id, shared_future<handle_ptr> handle, bool check_handle=true, bool validate=true) : _parent(parent), _id(id), _h(std::move(handle)) { if(validate) _validate(check_handle); }
01470     future(handle_ptr _handle, bool check_handle=true, bool validate=true) : _parent(_handle->parent()), _id((size_t)-1) { promise<handle_ptr> p; p.set_value(std::move(_handle)); _h=p.get_future(); if(validate) _validate(check_handle); }
01475     future(dispatcher *parent, size_t id) : _parent(parent), _id(id) { }
01477     future &operator=(const future &o) { _parent = o._parent; _id = o._id; _h = o._h; return *this; }
01479     future &operator=(future &&o) noexcept { _parent = std::move(o._parent); _id = std::move(o._id); _h = std::move(o._h); return *this; }
01480 
01482     bool valid() const noexcept { return _parent && _id; }
01484     explicit operator bool() const noexcept { return has_value(); }
01486     bool is_ready() const noexcept
01487     {
01488       return valid() || _h.wait_for(chrono::seconds(0)) == future_status::ready;
01489     }
01491     bool has_value() const noexcept { return is_ready() && !has_exception(); }
01493     bool has_error() const noexcept
01494     {
01495       if (!is_ready())
01496         return false;
01497       error_type ec = get_error();
01498       return ec && ec.category() != monad_category();
01499     }
01504     bool has_exception(bool only_exception = false) const noexcept
01505     {
01506       if (!is_ready())
01507         return false;
01508       return !!get_exception();
01509     }
01510 
01512     dispatcher *parent() const noexcept { return _parent; }
01514     size_t id() const noexcept { return _id; }
01516     handle_ptr get_handle(bool return_null_if_errored=false) const
01517     {
01518         if(!_parent && !_id)
01519             return handle_ptr();
01520         // std::shared_future in older libstdc++ does not have a const get().
01521         if(!return_null_if_errored)
01522             return const_cast<future *>(this)->_h.get();
01523         auto e=get_exception_ptr(_h);
01524         return e ? handle_ptr() : const_cast<future *>(this)->_h.get();
01525     }
01527     handle_ptr get_handle(error_type &ec) const
01528     {
01529       if (!_parent && !_id)
01530         return handle_ptr();
01531       ec = get_error();
01532       return ec ? handle_ptr() : const_cast<future *>(this)->_h.get();
01533     }
01535     const handle &operator *() const { return *get_handle(); }
01537     handle &operator *() { return *get_handle(); }
01539     const handle *operator->() const { return get_handle().get(); }
01541     handle *operator->() { return get_handle().get(); }
01543     void get()
01544     {
01545       if (!valid())
01546         throw future_error(future_errc::no_state);
01547       _h.get();
01548     }
01550     error_type get_error() const
01551     {
01552       if (!valid())
01553         throw future_error(future_errc::no_state);
01554       auto e = get_exception_ptr(_h);
01555       if (e)
01556       {
01557         try
01558         {
01559           rethrow_exception(e);
01560         }
01561         catch (const system_error &_e)
01562         {
01563           return _e.code();
01564         }
01565         catch (...)
01566         {
01567           return error_type((int)monad_errc::exception_present, monad_category());
01568         }
01569       }
01570       return error_type();
01571     }
01573     exception_type get_exception() const
01574     {
01575       if (!valid())
01576         throw future_error(future_errc::no_state);
01577       return get_exception_ptr(_h);
01578     }
01580     void wait() const
01581     {
01582       if (!valid())
01583         throw future_error(future_errc::no_state);
01584       _h.wait();
01585     }
01587     template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period> &duration) const
01588     {
01589       if (!valid())
01590         throw future_error(future_errc::no_state);
01591       return _h.wait_for(duration);
01592     }
01594     template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration> &deadline) const
01595     {
01596       if (!valid())
01597         throw future_error(future_errc::no_state);
01598       return _h.wait_until(deadline);
01599     }
01601     template<class U> auto then(U &&f) -> typename detail::continuation_return_type<decltype(f(*this))>::future_type
01602     {
01603       using future_type = typename detail::continuation_return_type<decltype(f(*this))>::future_type;
01604       using promise_type = typename detail::continuation_return_type<decltype(f(*this))>::promise_type;
01605       return detail::do_continuation<future_type, promise_type>()(parent(), this, std::forward<U>(f));
01606     }
01608     bool validate(bool check_handle=true) const
01609     {
01610         if(!valid()) return false;
01611         // If h is valid and ready and contains an exception, throw it now
01612         if(_h.valid() && BOOST_AFIO_V2_NAMESPACE::is_ready(_h))
01613         {
01614             if(check_handle)
01615                 if(!const_cast<shared_future<handle_ptr> &>(_h).get().get())
01616                     return false;
01617         }
01618         return true;
01619     }
01620 protected:
01621     void _validate(bool check_handle=true) const
01622     {
01623 #if BOOST_AFIO_VALIDATE_INPUTS
01624         if(!validate(check_handle))
01625             BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
01626 #endif
01627     }
01628 };
01659 template<class T> class future : public future<void>
01660 {
01661   stl_future<T> _result;
01662 public:
01664   using value_type = T;
01665 
01666   future() = default;
01675   future(dispatcher *parent, size_t id, shared_future<handle_ptr> handle, stl_future<T> result, bool check_handle = true, bool validate = true) : future<void>(parent, id, std::move(handle), check_handle, validate), _result(std::move(result)) { }
01680   future(future<void> &&o, stl_future<T> &&result) : future<void>(std::move(o)), _result(std::move(result)) { }
01682   bool valid(bool just_handle=false) const noexcept { return future<void>::valid() && (just_handle || _result.valid()); }
01684   T get()
01685   {
01686     return _result.get();
01687   }
01689   template<class U> auto then(U &&f) -> typename detail::continuation_return_type<decltype(f(*this))>::future_type
01690   {
01691     using future_type = typename detail::continuation_return_type<decltype(f(*this))>::future_type;
01692     using promise_type = typename detail::continuation_return_type<decltype(f(*this))>::promise_type;
01693     return detail::do_continuation<future_type, promise_type>()(parent(), this, std::forward<U>(f));
01694   }
01695 };
01696 
01697 namespace detail
01698 {
01699   // For continuations returning lightweight futures
01700   template<class future_type, class promise_type> struct do_continuation
01701   {
01702     template<class D, class U> future_type operator()(D *d, future<> *src, U &&f)
01703     {
01704       if (!d) d = current_dispatcher().get();
01705       auto p = std::make_shared<promise_type>();
01706       d->completion(*src, std::make_pair(async_op_flags::immediate, [f, p](size_t id, future<> _f) -> std::pair<bool, handle_ptr> {
01707         try
01708         {
01709           using result_type = decltype(f(_f));
01710           f(_f).then([p](const result_type &_f) {
01711             auto s(_f.get_state());
01712             try
01713             {
01714               p->set_state(std::move(s));
01715             }
01716             catch (...) { /* Really should filter for no_state but this is shim code */ }
01717           });
01718         }
01719         catch (...)
01720         {
01721           p->set_exception(current_exception());
01722         }
01723         return std::make_pair(true, _f.get_handle());
01724       }));
01725       return p->get_future();
01726     }
01727   };
01728   // For continuations returning shim AFIO futures or some naked type
01729   template<class R> struct do_continuation<future<R>, void>
01730   {
01731     template<class D, class T, class U> future<R> operator()(D *d, future<T> *src, U &&f)
01732     {
01733       if (!d) d = current_dispatcher().get();
01734       // TEMPORARY: For continuations taking a future<T> where T is not void
01735       // we have no way of passing the correct future to the continuation until
01736       // the lightweight future promise refactor
01737       //
01738       // So simply call the continuation now. When it calls .get() it will block.
01739       return f(*src);
01740     }
01741     template<class D, class U> future<> operator()(D *d, future<> *src, U &&f)
01742     {
01743       if (!d) d = current_dispatcher().get();
01744       return d->completion(*src, std::make_pair(async_op_flags::immediate, [f](size_t id, future<> _f) -> std::pair<bool, handle_ptr> {
01745         f(_f);
01746         return std::make_pair(true, _f.get_handle());
01747       }));
01748     }
01749   };
01750 }
01751 
01752 // This is a result_of filter to work around the weird mix of brittle decltype(), SFINAE incapable
01753 // std::result_of and variadic template overload resolution rules in VS2013. Works on other compilers
01754 // too of course, it simply prefilters out the call() overloads not matching the variadic overload.
01755 namespace detail
01756 {
01757 #if 0
01758     template<class C, class... Args> struct vs2013_variadic_overload_resolution_workaround;
01759     // Match callable
01760     template<class R, class... OArgs, class... Args> struct vs2013_variadic_overload_resolution_workaround<R (*)(OArgs...), Args...>
01761     {
01762         typedef typename std::result_of<R(*)(Args...)>::type type;
01763     };
01764     // Match callable
01765     template<class R, class T, class... OArgs, class... Args> struct vs2013_variadic_overload_resolution_workaround<R (T::*)(OArgs...) const, Args...>
01766     {
01767         typedef typename std::result_of<R (T::*)(Args...) const>::type type;
01768     };
01769     // Match callable
01770     template<class R, class T, class... OArgs, class... Args> struct vs2013_variadic_overload_resolution_workaround<R (T::*const)(OArgs...) const, Args...>
01771     {
01772         typedef typename std::result_of<R (T::*const)(Args...) const>::type type;
01773     };
01774 #else
01775     /*
01776     call(const std::vector<future> &ops             , const std::vector<std::function<R()>> &callables              );
01777     call(const std::vector<std::function<R()>> &callables                                                                );
01778     call(const future &req                          , std::function<R()> callback                                   );
01779     call(const future &req                          , C callback                                      , Args... args);
01780     */
01781     template<class C, class... Args> struct vs2013_variadic_overload_resolution_workaround
01782     {
01783         typedef typename std::result_of<C(Args...)>::type type;
01784     };
01785     // Disable C being a const std::vector<std::function<R()>> &callables
01786     template<class T, class... Args> struct vs2013_variadic_overload_resolution_workaround<std::vector<T>, Args...>;
01787 #endif
01788     template<class Impl, class Handle> handle_ptr decode_relative_path(path_req &req, bool force_absolute=false);
01789 }
01790 
01811 class BOOST_AFIO_DECL dispatcher : public std::enable_shared_from_this<dispatcher>
01812 {
01813     //friend BOOST_AFIO_DECL dispatcher_ptr async_file_io_dispatcher(thread_source &threadpool=process_threadpool(), file_flags flagsforce=file_flags::none, file_flags flagsmask=file_flags::none);
01814     template<class Impl, class Handle> friend handle_ptr detail::decode_relative_path(path_req &req, bool force_absolute);
01815     friend struct detail::async_io_handle_posix;
01816     friend struct detail::async_io_handle_windows;
01817     friend class detail::async_file_io_dispatcher_compat;
01818     friend class detail::async_file_io_dispatcher_windows;
01819     friend class detail::async_file_io_dispatcher_linux;
01820     friend class detail::async_file_io_dispatcher_qnx;
01821 
01822     detail::dispatcher_p *p;
01823     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void int_directory_cached_handle_path_changed(path oldpath, path newpath, handle_ptr h);
01824     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void int_add_io_handle(void *key, handle_ptr h);
01825     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void int_del_io_handle(void *key);
01826     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC future<> int_op_from_scheduled_id(size_t id) const;
01827 
01828 protected:
01829     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC dispatcher(std::shared_ptr<thread_source> threadpool, file_flags flagsforce, file_flags flagsmask);
01830     std::pair<bool, handle_ptr> doadopt(size_t, future<>, handle_ptr h)
01831     {
01832         return std::make_pair(true, h);
01833     }
01834 public:
01835     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void testing_flags(detail::unit_testing_flags flags);
01837     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC ~dispatcher();
01838 
01840     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::shared_ptr<thread_source> threadsource() const;
01842     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC file_flags fileflags(file_flags flags) const;
01844     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC size_t wait_queue_depth() const;
01846     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC size_t fd_count() const;
01847 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01848     /* \brief Returns an op ref for a given \b currently scheduled op id, throwing an exception if id not scheduled at the point of call.
01849     Can be used to retrieve exception state from some op id, or one's own shared stl_future.
01850     
01851     \return An future<> with the same shared stl_future as all op refs with this id.
01852     \param id The unique integer id for the op.
01853     */
01854     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC future<> op_from_scheduled_id(size_t id) const;
01855 
01856     // The type of an op filter callback handler \ingroup dispatcher__filter
01857     typedef void filter_t(detail::OpType, future<> &);
01858     // The type of a readwrite filter callback handler \ingroup dispatcher__filter
01859     typedef void filter_readwrite_t(detail::OpType, handle *, const detail::io_req_impl<true> &, off_t, size_t, size_t, const error_code &, size_t);
01860     /* \brief Clears the post op and readwrite filters. Not threadsafe.
01861 
01862     \ingroup dispatcher__filter
01863     \complexity{O(1).}
01864     \qexample{filter_example}
01865     */
01866     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void post_op_filter_clear();
01867     /* \brief Install op filters for non-buffer taking ops. Not threadsafe.
01868 
01869     `std::function<dispatcher::filter_t>` will be called after every op of type `detail::OpType`
01870     completes (`detail::OpType::Unknown` means call this filter for all ops) with the op type and op output.
01871 
01872     Note that filters are currently implemented as a linear scan, so a full iteration of all filters is done
01873     for every op completed. The filter is called straight after an op's stl_future is set and before any completions
01874     are issued. Any exceptions thrown by the filter are thrown away.
01875 
01876     \param filters A batch of pairs of op type to be filtered and bound filter handler functions of type `filter_t`
01877     \ingroup dispatcher__filter
01878     \complexity{O(N) where N is the total number of filters currently configured.}
01879     \qexample{filter_example}
01880     */
01881     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void post_op_filter(std::vector<std::pair<detail::OpType, std::function<dispatcher::filter_t>>> filters);
01882     /* \brief Install read/write op filters, useful for tight ASIO integration. Not threadsafe.
01883 
01884     `std::function<dispatcher::filter_buffers_t>` will be called after every op of type `detail::OpType`
01885     completes (`detail::OpType::Unknown` means call this filter for all ops) with the op type, file handle, op input, 
01886     file offset, buffers offset, buffers amount, error state and bytes transferred. Any filter other than read() and write()
01887     will be ignored, for those use post_op_filter().
01888 
01889     Note that buffer filters are currently implemented as a linear scan, so a full iteration of all buffer filters is done
01890     for every read/write op completed. The filter is called straight after a read or write operation has completed, and
01891     BEFORE any checks that it transferred the data it was supposed to. Any exceptions thrown by the filter are reported
01892     as if the read/write operation threw them, and filter processing stops at the filter which threw.
01893 
01894     \param filters A batch of pairs of op type to be filtered and bound filter handler functions of type `filter_buffers_t`
01895     \ingroup dispatcher__filter
01896     \complexity{O(N) where N is the total number of filters currently configured.}
01897     \qexample{filter_example}
01898     */
01899     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void post_readwrite_filter(std::vector<std::pair<detail::OpType, std::function<dispatcher::filter_readwrite_t>>> filters);
01900 
01901     // The type returned by a completion handler \ingroup dispatcher__completion
01902     typedef std::pair<bool, handle_ptr> completion_returntype;
01903     // The type of a completion handler \ingroup dispatcher__completion
01904     typedef completion_returntype completion_t(size_t, future<>);
01905 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01906 #if defined(BOOST_AFIO_ENABLE_BENCHMARKING_COMPLETION) || BOOST_AFIO_HEADERS_ONLY==0 // Only really used for benchmarking
01907     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> completion(const std::vector<future<>> &ops, const std::vector<std::pair<async_op_flags, dispatcher::completion_t *>> &callbacks);
01908     inline future<> completion(const future<> &req, const std::pair<async_op_flags, dispatcher::completion_t *> &callback);
01909 #endif
01910 #endif
01911     /* \brief Schedule a batch of asynchronous invocations of the specified functions when their supplied operations complete.
01912 
01913     \deprecate{This function will be eliminated after lightweight future-promises are merged as one simply calls .then() on the future.}
01914     \return A batch of op handles
01915     \param ops A batch of precondition op handles.
01916     \param callbacks A batch of pairs of op flags and bound completion handler functions of type `completion_t`
01917     \ingroup dispatcher__completion
01918     \qbk{distinguish, batch bound functions}
01919     \complexity{Amortised O(N) to dispatch. Amortised O(N/threadpool) to complete.}
01920     \exceptionmodelstd
01921     \qexample{completion_example1}
01922     */
01923     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> completion(const std::vector<future<>> &ops, const std::vector<std::pair<async_op_flags, std::function<dispatcher::completion_t>>> &callbacks);
01924     /* \brief Schedule the asynchronous invocation of the specified single function when the supplied single operation completes.
01925 
01926     \deprecate{This function will be eliminated after lightweight future-promises are merged as one simply calls .then() on the future.}
01927     \return An op handle
01928     \param req A precondition op handle
01929     \param callback A pair of op flag and bound completion handler function of type `completion_t`
01930     \ingroup dispatcher__completion
01931     \qbk{distinguish, single bound function}
01932     \complexity{Amortised O(1) to dispatch. Amortised O(1) to complete.}
01933     \exceptionmodelstd
01934     \qexample{completion_example1}
01935     */
01936     inline future<> completion(const future<> &req, const std::pair<async_op_flags, std::function<dispatcher::completion_t>> &callback);
01937 
01938     /* \brief Schedule a batch of asynchronous invocations of the specified bound functions when their supplied preconditions complete.
01939 
01940     \deprecate{This function will be eliminated after lightweight future-promises are merged as one simply calls .then() on the future.}
01941     This is effectively a convenience wrapper for `completion()`. It creates an enqueued_task matching the `completion_t`
01942     handler specification and calls the specified arbitrary callable, always returning completion on exit.
01943     
01944     \return A pair with a batch of futures returning the result of each of the callables and a batch of op handles.
01945     \tparam "class R" A compiler deduced return type of the bound functions.
01946     \param ops A batch of precondition op handles. If default constructed, a precondition is null.
01947     \param callables A batch of bound functions to call, returning R.
01948     \ingroup dispatcher__call
01949     \qbk{distinguish, batch bound functions}
01950     \complexity{Amortised O(N) to dispatch. Amortised O(N/threadpool) to complete.}
01951     \exceptionmodelstd
01952     \qexample{call_example}
01953     */
01954     template<class R> inline std::vector<future<R>> call(const std::vector<future<>> &ops, const std::vector<std::function<R()>> &callables);
01955     /* \brief Schedule a batch of asynchronous invocations of the specified bound functions when their supplied preconditions complete.
01956 
01957     \deprecate{This function will be eliminated after lightweight future-promises are merged as one simply calls .then() on the future.}
01958     This is effectively a convenience wrapper for `completion()`. It creates an enqueued_task matching the `completion_t`
01959     handler specification and calls the specified arbitrary callable, always returning completion on exit. If you
01960     are seeing performance issues, using `completion()` directly will have much less overhead.
01961     
01962     \return A pair with a batch of futures returning the result of each of the callables and a batch of op handles.
01963     \tparam "class R" A compiler deduced return type of the bound functions.
01964     \param callables A batch of bound functions to call, returning R.
01965     \ingroup dispatcher__call
01966     \qbk{distinguish, batch bound functions without preconditions}
01967     \complexity{Amortised O(N) to dispatch. Amortised O(N/threadpool) to complete.}
01968     \exceptionmodelstd
01969     \qexample{call_example}
01970     */
01971     template<class R> std::vector<future<R>> call(const std::vector<std::function<R()>> &callables) { return call(std::vector<future<>>(), callables); }
01972     /* \brief Schedule an asynchronous invocation of the specified bound function when its supplied precondition completes.
01973 
01974     \deprecate{This function will be eliminated after lightweight future-promises are merged as one simply calls .then() on the future.}
01975     This is effectively a convenience wrapper for `completion()`. It creates an enqueued_task matching the `completion_t`
01976     handler specification and calls the specified arbitrary callable, always returning completion on exit. If you
01977     are seeing performance issues, using `completion()` directly will have much less overhead.
01978     
01979     \return A pair with a stl_future returning the result of the callable and an op handle.
01980     \tparam "class R" A compiler deduced return type of the bound functions.
01981     \param req A precondition op handle. If default constructed, the precondition is null.
01982     \param callback A bound functions to call, returning R.
01983     \ingroup async_file_io_dispatcher__call
01984     \qbk{distinguish, single bound function}
01985     \complexity{Amortised O(1) to dispatch. Amortised O(1) to complete.}
01986     \exceptionmodelstd
01987     \qexample{call_example}
01988     */
01989     template<class R> inline future<R> call(const future<> &req, std::function<R()> callback);
01990 
01991     
01992     
01993          
01994     /* \brief Schedule an asynchronous invocation of the specified unbound callable when its supplied precondition completes.
01995     Note that this function essentially calls `std::bind()` on the callable and the args and passes it to the other call() overload taking a `std::function<>`.
01996     You should therefore use `std::ref()` etc. as appropriate.
01997 
01998     This is effectively a convenience wrapper for `completion()`. It creates an enqueued_task matching the `completion_t`
01999     handler specification and calls the specified arbitrary callable, always returning completion on exit. If you
02000     are seeing performance issues, using `completion()` directly will have much less overhead.
02001     
02002     \return A pair with a stl_future returning the result of the callable and an op handle.
02003     \tparam "class C" Any callable type.
02004     \tparam Args Any sequence of argument types.
02005     \param req A precondition op handle. If default constructed, the precondition is null.
02006     \param callback An unbound callable to call.
02007     \param args An arbitrary sequence of arguments to bind to the callable.
02008     \ingroup dispatcher__call
02009     \qbk{distinguish, single unbound callable}
02010     \complexity{Amortised O(1) to dispatch. Amortised O(1) to complete.}
02011     \exceptionmodelstd
02012     \qexample{call_example}
02013     */
02014 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02015     template<class C, class... Args> inline future<typename detail::vs2013_variadic_overload_resolution_workaround<C, Args...>::type> call(const future<> &req, C callback, Args... args);
02016 #else
02017     template<class C, class... Args> inline future<typename std::result_of<C(Args...)>::type> call(const future<> &req, C callback, Args... args);
02018 #endif
02019 
02020 
02021 
02022     /* \brief Schedule a batch of third party handle adoptions.
02023 
02024     \docs_adopt
02025 
02026     \return A batch of op handles.
02027     \param hs A batch of handles to adopt.
02028     \ingroup dispatcher__filedirops
02029     \qbk{distinguish, batch}
02030     \complexity{Amortised O(N) to dispatch. Amortised O(N/threadpool) to complete.}
02031     \exceptionmodelstd
02032     \qexample{adopt_example}
02033     */
02034     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> adopt(const std::vector<handle_ptr> &hs);
02035 #endif
02036 
02053     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> dir(const std::vector<path_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02072     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> rmdir(const std::vector<path_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02090     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> file(const std::vector<path_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02109     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> rmfile(const std::vector<path_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02128     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> symlink(const std::vector<path_req> &reqs, const std::vector<future<>> &targets=std::vector<future<>>()) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02145     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> rmsymlink(const std::vector<path_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02158     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> sync(const std::vector<future<>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02172     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> zero(const std::vector<future<>> &ops, const std::vector<std::vector<std::pair<off_t, off_t>>> &ranges) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02185     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> close(const std::vector<future<>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02186 
02202 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02203     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> read(const std::vector<detail::io_req_impl<false>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02204     template<class T> inline std::vector<future<>> read(const std::vector<io_req<T>> &ops);
02205 #else
02206     template<class T> BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> read(const std::vector<io_req<T>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02207 #endif
02208 
02223 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02224     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> write(const std::vector<detail::io_req_impl<true>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02225     template<class T> inline std::vector<future<>> write(const std::vector<io_req<T>> &ops);
02226 #else
02227     template<class T> BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> write(const std::vector<io_req<const T>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02228 #endif
02229 
02243     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> truncate(const std::vector<future<>> &ops, const std::vector<off_t> &sizes) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02244     
02264     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<std::pair<std::vector<directory_entry>, bool>>> enumerate(const std::vector<enumerate_req> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02283     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<std::vector<std::pair<off_t, off_t>>>> extents(const std::vector<future<>> &ops) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02304     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<statfs_t>> statfs(const std::vector<future<>> &ops, const std::vector<fs_metadata_flags> &reqs) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02305 
02306 #ifndef DOXYGEN_SHOULD_SKIP_THIS
02307     inline future<> adopt(handle_ptr h);
02308     inline future<> dir(const path_req &req);
02309     inline future<> rmdir(const path_req &req);
02310     inline future<> file(const path_req &req);
02311     inline future<> rmfile(const path_req &req);
02312     inline future<> symlink(const path_req &req, const future<> &target=future<>());
02313     inline future<> rmsymlink(const path_req &req);
02314     inline future<> sync(const future<> &req);
02315     inline future<> zero(const future<> &req, const std::vector<std::pair<off_t, off_t>> &ranges);
02316     inline future<> close(const future<> &req);
02317     inline future<> read(const detail::io_req_impl<false> &req);
02318     inline future<> write(const detail::io_req_impl<true> &req);
02319     inline future<> truncate(const future<> &op, off_t newsize);
02320     inline future<std::pair<std::vector<directory_entry>, bool>> enumerate(const enumerate_req &req);
02321     inline future<std::vector<std::pair<off_t, off_t>>> extents(const future<> &op);
02322     inline future<statfs_t> statfs(const future<> &op, const fs_metadata_flags &req);
02323 
02324     // Undocumented deliberately
02325     BOOST_AFIO_HEADERS_ONLY_VIRTUAL_SPEC std::vector<future<>> lock(const std::vector<lock_req> &req) BOOST_AFIO_HEADERS_ONLY_VIRTUAL_UNDEFINED_SPEC
02326 
02327     
02347     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> barrier(const std::vector<future<>> &ops);
02348 #endif
02349 
02361     inline future<> depends(future<> precondition, future<> op);
02362 
02370     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC void complete_async_op(size_t id, handle_ptr h, exception_ptr e=exception_ptr());
02378     void complete_async_op(size_t id, exception_ptr e) { complete_async_op(id, handle_ptr(), e); }
02379 protected:
02380     template<class F> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC handle_ptr int_get_handle_to_containing_dir(F *parent, size_t id, path_req req, completion_returntype(F::*dofile)(size_t, future<>, path_req));
02381     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC completion_returntype invoke_user_completion_fast(size_t id, future<> h, completion_t *callback);
02382     BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC completion_returntype invoke_user_completion_slow(size_t id, future<> h, std::function<completion_t> callback);
02383 
02384     template<class F> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> chain_async_ops(int optype, const std::vector<future<>> &preconditions, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, future<>));
02385     template<class F, class T> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> chain_async_ops(int optype, const std::vector<future<>> &preconditions, const std::vector<T> &container, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, T));
02386     template<class R, class F> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<R>> chain_async_ops(int optype, const std::vector<future<>> &preconditions, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, std::shared_ptr<promise<R>>));
02387     template<class R, class F, class T> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<R>> chain_async_ops(int optype, const std::vector<future<>> &preconditions, const std::vector<T> &container, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, T, std::shared_ptr<promise<R>>));
02388     template<class F, class T> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<>> chain_async_ops(int optype, const std::vector<T> &container, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, T));
02389     template<class R, class F, class T> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC std::vector<future<R>> chain_async_ops(int optype, const std::vector<T> &container, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, T, std::shared_ptr<promise<R>>));
02390 
02391     template<class T> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC dispatcher::completion_returntype dobarrier(size_t id, future<> h, T);
02392     template<class F, class... Args> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC handle_ptr invoke_async_op_completions(size_t id, future<> h, completion_returntype(F::*f)(size_t, future<>, Args...), Args... args);
02393     template<class F, class... Args> BOOST_AFIO_HEADERS_ONLY_MEMFUNC_SPEC future<> chain_async_op(detail::immediate_async_ops &immediates, int optype, const future<> &precondition, async_op_flags flags, completion_returntype(F::*f)(size_t, future<>, Args...), Args... args);
02394 };
02415 #ifdef DOXYGEN_SHOULD_SKIP_THIS
02416 BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC outcome<dispatcher_ptr> make_dispatcher(std::string uri="file : / / /", file_flags flagsforce = file_flags::none, file_flags flagsmask = file_flags::none, std::shared_ptr<thread_source> threadpool = process_threadpool()) noexcept;
02417 #else
02418 BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC outcome<dispatcher_ptr> make_dispatcher(std::string uri="file:///", file_flags flagsforce=file_flags::none, file_flags flagsmask=file_flags::none, std::shared_ptr<thread_source> threadpool = process_threadpool()) noexcept;
02419 #endif
02420 
02421 namespace detail
02422 {
02423     struct when_all_state : std::enable_shared_from_this<when_all_state>
02424     {
02425         promise<std::vector<handle_ptr>> out;
02426         std::vector<shared_future<handle_ptr>> in;
02427     };
02428     template<bool rethrow> inline void when_all_ops_do(std::shared_ptr<when_all_state> state)
02429     {
02430         // If we're on Boost.Thread, coalesce all wait ops into a single
02431 #if BOOST_AFIO_USE_BOOST_THREAD
02432         boost::wait_for_all(state->in.begin(), state->in.end());
02433 #endif
02434         std::vector<handle_ptr> ret;
02435         ret.reserve(state->in.size());
02436         for(auto &i: state->in)
02437         {
02438             auto e(get_exception_ptr(i));
02439             if(e)
02440             {
02441                 if(rethrow)
02442                 {
02443                     state->out.set_exception(e);
02444                     return;
02445                 }
02446                 ret.push_back(handle_ptr());
02447             }
02448             else
02449                 ret.push_back(i.get());
02450         }
02451         state->out.set_value(ret);
02452     }
02453     template<bool rethrow, class Iterator> inline stl_future<std::vector<handle_ptr>> when_all_ops(Iterator first, Iterator last)
02454     {
02455         auto state=std::make_shared<when_all_state>();
02456         state->in.reserve(std::distance(first, last));
02457         for(; first!=last; ++first)
02458             state->in.push_back(first->_h);
02459         auto ret=state->out.get_future();
02460         process_threadpool()->enqueue([BOOST_AFIO_LAMBDA_MOVE_CAPTURE(state)] { when_all_ops_do<rethrow>(std::move(state)); });
02461         return ret;
02462     }
02463     struct when_any_state : std::enable_shared_from_this<when_any_state>
02464     {
02465         atomic<size_t> count;
02466         promise<handle_ptr> out;
02467         std::vector<shared_future<handle_ptr>> in;
02468         when_any_state() : count(0) { }
02469     };
02470 #if BOOST_AFIO_USE_BOOST_THREAD
02471     // Boost.Thread has wait_for_any() which lets us be more efficient here and wait directly on the futures
02472     template<bool rethrow> inline void when_any_ops_do(std::shared_ptr<when_any_state> state)
02473     {
02474         auto &i=*boost::wait_for_any(state->in.begin(), state->in.end());
02475         auto e(get_exception_ptr(i));
02476         if(e)
02477         {
02478             if(rethrow)
02479             {
02480                 state->out.set_exception(e);
02481                 return;
02482             }
02483             state->out.set_value(handle_ptr());
02484         }
02485         else
02486             state->out.set_value(i.get());
02487     }
02488     template<bool rethrow, class Iterator> inline stl_future<handle_ptr> when_any_ops(Iterator first, Iterator last)
02489     {
02490         auto state=std::make_shared<when_any_state>();
02491         state->in.reserve(std::distance(first, last));
02492         for(; first!=last; ++first)
02493             state->in.push_back(first->h);
02494         auto ret=state->out.get_future();
02495         process_threadpool()->enqueue([BOOST_AFIO_LAMBDA_MOVE_CAPTURE(state)]{ when_any_ops_do<rethrow>(std::move(state)); });
02496         return ret;
02497     }
02498 #else
02499     // Without wait_for_any, schedule a completion onto every op and the first to fire wins
02500     template<bool rethrow> inline std::pair<bool, handle_ptr> when_any_ops_do(std::shared_ptr<when_any_state> state, size_t idx, size_t id, future<> h)
02501     {
02502         auto &i=state->in[idx];
02503         if(0==state->count.fetch_add(1, memory_order_relaxed))  // Will be zero exactly once
02504         {
02505             auto e(get_exception_ptr(i));
02506             if(e)
02507             {
02508                 if(rethrow)
02509                 {
02510                     state->out.set_exception(e);
02511                     return std::make_pair(true, handle_ptr());
02512                 }
02513                 state->out.set_value(handle_ptr());
02514             }
02515             else
02516                 state->out.set_value(i.get());
02517         }
02518         return std::make_pair(true, handle_ptr());
02519     }
02520     template<bool rethrow, class Iterator> inline stl_future<handle_ptr> when_any_ops(Iterator first, Iterator last)
02521     {
02522         auto state=std::make_shared<when_any_state>();
02523         auto dispatcher=first->parent();
02524         std::vector<future<>> ops(first, last);
02525         state->in.reserve(ops.size());
02526         for(auto &op : ops)
02527             state->in.push_back(op._h);
02528         auto ret=state->out.get_future();
02529         typedef std::function<typename dispatcher::completion_t> ft;
02530         std::vector<std::pair<async_op_flags, ft>> completions;
02531         completions.reserve(ops.size());
02532         for(size_t n=0; n<ops.size(); n++)
02533           completions.push_back(std::make_pair(async_op_flags::immediate, std::bind(&when_any_ops_do<rethrow>, state, n, std::placeholders::_1, std::placeholders::_2)));
02534         dispatcher->completion(ops, completions);
02535         return ret;
02536     }
02537 #endif
02538     template<bool is_all> struct select_when_ops_return_type
02539     {
02540         typedef stl_future<std::vector<handle_ptr>> type; // when_all_p()
02541     };
02542     template<> struct select_when_ops_return_type<false>
02543     {
02544         typedef stl_future<handle_ptr> type; // when_any()
02545     };
02546     template<bool is_all, class T> struct enable_if_async_op
02547     {
02548         //static_assert(std::is_same<T, T>::value, "Not an iterator of future<>");
02549     };
02550     template<bool is_all, class T> struct enable_if_async_op<is_all, future<T>>
02551     {
02552         typedef typename select_when_ops_return_type<is_all>::type type;
02553     };
02554 }
02555 
02569 template<class Iterator> inline typename detail::enable_if_async_op<true, typename Iterator::value_type>::type when_all_p(std::nothrow_t _, Iterator first, Iterator last)
02570 {
02571     if(first==last)
02572         return stl_future<std::vector<handle_ptr>>();
02573     return detail::when_all_ops<false>(first, last);
02574 }
02588 template<class Iterator> inline typename detail::enable_if_async_op<false, typename Iterator::value_type>::type when_any(std::nothrow_t _, Iterator first, Iterator last)
02589 {
02590     if(first==last)
02591         return stl_future<handle_ptr>();
02592     return detail::when_any_ops<false>(first, last);
02593 }
02605 template<class T> inline stl_future<std::vector<handle_ptr>> when_all_p(std::nothrow_t _, std::vector<future<T>> ops)
02606 {
02607     if(ops.empty())
02608         return stl_future<std::vector<handle_ptr>>();
02609     return detail::when_all_ops<false>(ops.begin(), ops.end());
02610 }
02622 template<class T> inline stl_future<handle_ptr> when_any(std::nothrow_t _, std::vector<future<T>> ops)
02623 {
02624     if(ops.empty())
02625         return stl_future<handle_ptr>();
02626     return detail::when_any_ops<false>(ops.begin(), ops.end());
02627 }
02640 template<class Iterator> inline typename detail::enable_if_async_op<true, typename Iterator::value_type>::type when_all_p(Iterator first, Iterator last)
02641 {
02642     if(first==last)
02643         return stl_future<std::vector<handle_ptr>>();
02644     return detail::when_all_ops<true>(first, last);
02645 }
02658 template<class Iterator> inline typename detail::enable_if_async_op<false, typename Iterator::value_type>::type when_any(Iterator first, Iterator last)
02659 {
02660     if(first==last)
02661         return stl_future<handle_ptr>();
02662     return detail::when_any_ops<true>(first, last);
02663 }
02674 template<class T> inline stl_future<std::vector<handle_ptr>> when_all_p(std::vector<future<T>> ops)
02675 {
02676     if(ops.empty())
02677         return stl_future<std::vector<handle_ptr>>();
02678     return detail::when_all_ops<true>(ops.begin(), ops.end());
02679 }
02690 template<class T> inline stl_future<handle_ptr> when_any(std::vector<future<T>> ops)
02691 {
02692     if(ops.empty())
02693         return stl_future<handle_ptr>();
02694     return detail::when_any_ops<true>(ops.begin(), ops.end());
02695 }
02707 template<class T> inline stl_future<std::vector<handle_ptr>> when_all_p(std::nothrow_t _, future<T> op)
02708 {
02709     std::vector<future<T>> ops(1, op);
02710     return when_all_p(_, ops);
02711 }
02722 template<class... Types> inline stl_future<std::vector<handle_ptr>> when_all_p(future<Types> &... ops)
02723 {
02724     std::vector<future<>> _ops = { std::forward<future<Types> &>(ops)... };
02725     return when_all_p(_ops);
02726 }
02727 
02737 struct path_req
02738 {
02739     bool is_relative;           
02740     BOOST_AFIO_V2_NAMESPACE::path path;            
02741     file_flags flags;           
02742     future<> precondition;   
02743 
02744     struct absolute;
02746     struct relative;
02748     path_req() : is_relative(false), flags(file_flags::none) { }
02750     path_req(const path_req &o) = default;
02752     path_req(path_req &&o) noexcept : is_relative(o.is_relative), path(std::move(o.path)), flags(std::move(o.flags)), precondition(std::move(o.precondition)) { }
02754     inline path_req(absolute &&o);
02756     inline path_req(relative &&o);
02764     template<class T, typename=typename std::enable_if<!std::is_constructible<path_req, T>::value && !std::is_constructible<future<>, T>::value>::type> path_req(T &&_path, file_flags _flags=file_flags::none) : is_relative(false), path(BOOST_AFIO_V2_NAMESPACE::path::make_absolute(std::forward<T>(_path))), flags(_flags) { }
02773     template<class T, typename=typename std::enable_if<!std::is_convertible<BOOST_AFIO_V2_NAMESPACE::path, T>::value>::type> path_req(bool _is_relative, future<> _precondition, T &&_path, file_flags _flags=file_flags::none) : is_relative(_is_relative), path(_is_relative ? BOOST_AFIO_V2_NAMESPACE::path(std::forward<T>(_path)) : BOOST_AFIO_V2_NAMESPACE::path(BOOST_AFIO_V2_NAMESPACE::path::make_absolute(std::forward<T>(_path)))), flags(_flags), precondition(std::move(_precondition)) { _validate(); }
02775     path_req(bool _is_relative, future<> _precondition, BOOST_AFIO_V2_NAMESPACE::path _path, file_flags _flags=file_flags::none) : is_relative(_is_relative), path(std::move(_path)), flags(_flags), precondition(std::move(_precondition)) { _validate(); }
02781     path_req(future<> _precondition, file_flags _flags=file_flags::none) : is_relative(true), flags(_flags), precondition(std::move(_precondition)) { _validate(); }
02783     bool validate() const
02784     {
02785         if(!is_relative && path.empty()) return false;
02786         return !precondition.valid() || precondition.validate();
02787     }
02788 protected:
02789     void _validate() const
02790     {
02791 #if BOOST_AFIO_VALIDATE_INPUTS
02792         if(!validate())
02793             BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
02794 #endif
02795     }
02796 };
02798 struct path_req::relative : path_req
02799 {
02807   template<class T> relative(future<> _precondition, T &&_path, file_flags _flags=file_flags::none) : path_req(true, std::move(_precondition), std::forward<T>(_path), _flags) { _validate(); }
02813   relative(future<> _precondition, file_flags _flags=file_flags::none) : path_req(std::move(_precondition), _flags) { _validate(); }
02814 };
02816 struct path_req::absolute : path_req
02817 {
02825   template<class T> absolute(future<> _precondition, T &&_path, file_flags _flags=file_flags::none) : path_req(false, std::move(_precondition), std::move(BOOST_AFIO_V2_NAMESPACE::path::make_absolute(std::forward<T>(_path))), _flags) { _validate(); }
02826 };
02827 inline path_req::path_req(path_req::absolute &&o) : is_relative(o.is_relative), path(std::move(o.path)), flags(std::move(o.flags)), precondition(std::move(o.precondition)) { }
02828 inline path_req::path_req(path_req::relative &&o) : is_relative(o.is_relative), path(std::move(o.path)), flags(std::move(o.flags)), precondition(std::move(o.precondition)) { }
02829 
02849 template<class T> inline std::vector<asio::mutable_buffer> to_asio_buffers(T &v);
02850 template<class T> inline std::vector<asio::const_buffer> to_asio_buffers(const T &v);
02851 template<class T, size_t N> inline std::vector<asio::mutable_buffer> to_asio_buffers(T (&v)[N]);
02852 template<class T, size_t N> inline std::vector<asio::const_buffer> to_asio_buffers(const T (&v)[N]);
02859 inline std::vector<asio::mutable_buffer> to_asio_buffers(asio::mutable_buffer &v)
02860 {
02861   return std::vector<asio::mutable_buffer>(1, v);
02862 }
02869 inline std::vector<asio::const_buffer> to_asio_buffers(asio::const_buffer &v)
02870 {
02871   return std::vector<asio::const_buffer>(1, v);
02872 }
02880 template<class T> inline std::vector<asio::mutable_buffer> to_asio_buffers(T *v, size_t length)
02881 {
02882   static_assert(std::is_trivial<T>::value, "to_asio_buffers<T> has not been specialised for this non-trivial type, which suggests you are trying to read or write a complex C++ type! Either add a custom specialisation, or directly instantiate an io_req with a void * and size_t length to some serialised representation.");
02883   return std::vector<asio::mutable_buffer>(1, asio::mutable_buffer((void *) v, length*sizeof(T)));
02884 }
02892 template<class T> inline std::vector<asio::const_buffer> to_asio_buffers(const T *v, size_t length)
02893 {
02894   static_assert(std::is_trivial<T>::value, "to_asio_buffers<T> has not been specialised for this non-trivial type, which suggests you are trying to read or write a complex C++ type! Either add a custom specialisation, or directly instantiate an io_req with a void * and size_t length to some serialised representation.");
02895   return std::vector<asio::const_buffer>(1, asio::const_buffer((void *) v, length*sizeof(T)));
02896 }
02903 inline std::vector<asio::mutable_buffer> to_asio_buffers(void *v, size_t length)
02904 {
02905   return std::vector<asio::mutable_buffer>(1, asio::mutable_buffer(v, length));
02906 }
02913 inline std::vector<asio::const_buffer> to_asio_buffers(const void *v, size_t length)
02914 {
02915   return std::vector<asio::const_buffer>(1, asio::const_buffer(v, length));
02916 }
02917 namespace detail
02918 {
02919     // Length deducing asio buffer conversions
02920     template<bool is_const, class R, class T, bool is_trivial=std::is_trivial<T>::value, bool is_container=is_container<T>::value> struct to_asio_buffers_helper
02921     {
02922       template<class U> std::vector<R> operator()(U &v) const
02923       {
02924         static_assert(!std::is_same<T, T>::value, "to_asio_buffers(T) called with type T which is neither trivial nor a container. Did you mean to call io_req with a void * and a byte length, or do you need to overload to_asio_buffers()?");
02925         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This type is const, so you cannot generate an asio::mutable_buffer from it.");
02926         return std::vector<R>();
02927       }
02928     };
02929     // Trivial types get sent as is
02930     template<bool is_const, class R, class T> struct to_asio_buffers_helper<is_const, R, T, true, false>
02931     {
02932       template<class U> std::vector<R> operator()(U &v) const
02933       {
02934         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This type is const, so you cannot generate an asio::mutable_buffer from it.");
02935         return std::vector<R>(1, R(&v, sizeof(v)));
02936       }
02937     };
02938 
02939     // Container types build a scatter gather list of their contents
02940     template<class R, class C, class T, bool is_const=std::is_const<T>::value, bool is_trivial=std::is_trivial<T>::value> struct container_to_asio_buffers_helper
02941     {
02942       template<class U> std::vector<R> operator()(U &v) const
02943       {
02944         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This container only permits const access to its iterators, so you cannot generate an asio::mutable_buffer from it.");
02945         std::vector<R> ret;
02946         for(auto &i : v)
02947         {
02948           std::vector<R> item(to_asio_buffers(i));
02949           ret.reserve(ret.size()+item.size());
02950           ret.insert(ret.end(), std::make_move_iterator(item.begin()), std::make_move_iterator(item.end()));
02951         }
02952         return ret;
02953       }
02954     };
02955     // Container specialisations where we know we can skip scatter gather
02956     template<class R, class C, class T, class A, class _Ct, bool is_const> struct container_to_asio_buffers_helper<R, std::basic_string<C, T, A>, _Ct, is_const, true>
02957     {
02958       template<class U> std::vector<R> operator()(U &v) const
02959       {
02960         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This container only permits const access to its iterators, so you cannot generate an asio::mutable_buffer from it.");
02961         return std::vector<R>(1, R(&v.front(), v.size()*sizeof(C)));
02962       }
02963     };
02964     template<class R, class T, class A, class _T, bool is_const> struct container_to_asio_buffers_helper<R, std::vector<T, A>, _T, is_const, true>
02965     {
02966       template<class U> std::vector<R> operator()(U &v) const
02967       {
02968         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This container only permits const access to its iterators, so you cannot generate an asio::mutable_buffer from it.");
02969         return std::vector<R>(1, R(v.data(), v.size()*sizeof(T)));
02970       }
02971     };
02972     template<class R, class T, size_t N, class _T, bool is_const> struct container_to_asio_buffers_helper<R, std::array<T, N>, _T, is_const, true>
02973     {
02974       template<class U> std::vector<R> operator()(U &v) const
02975       {
02976         static_assert(!std::is_same<asio::mutable_buffer, R>::value || !is_const, "This container only permits const access to its iterators, so you cannot generate an asio::mutable_buffer from it.");
02977         std::vector<R> ret(1, R(v.data(), v.size()*sizeof(T)));
02978         return ret;
02979       }
02980     };
02981     template<bool is_const, class R, class T, bool is_trivial> struct to_asio_buffers_helper<is_const, R, T, is_trivial, true> : container_to_asio_buffers_helper<R, T, typename is_container<T>::type>
02982     {
02983     };
02984     // Pass through vectors and arrays of asio buffers
02985     template<bool is_const, class R> struct to_asio_buffers_helper<is_const, R, std::vector<asio::mutable_buffer>, false, true>
02986     {
02987       template<class U> std::vector<R> operator()(U &v) const
02988       {
02989         std::vector<R> ret(v.begin(), v.end());
02990         return ret;
02991       }
02992     };
02993     template<bool is_const> struct to_asio_buffers_helper<is_const, asio::mutable_buffer, std::vector<asio::mutable_buffer>, false, true>
02994     {
02995       template<class U> std::vector<asio::mutable_buffer> operator()(U &v) const
02996       {
02997         return v;
02998       }
02999     };
03000     template<bool is_const, class R> struct to_asio_buffers_helper<is_const, R, std::vector<asio::const_buffer>, false, true>
03001     {
03002       template<class U> std::vector<R> operator()(U &v) const
03003       {
03004         std::vector<R> ret(v.begin(), v.end());
03005         return ret;
03006       }
03007     };
03008     template<bool is_const> struct to_asio_buffers_helper<is_const, asio::const_buffer, std::vector<asio::const_buffer>, false, true>
03009     {
03010       template<class U> std::vector<asio::const_buffer> operator()(U &v) const
03011       {
03012         return v;
03013       }
03014     };
03015     template<bool is_const, size_t N, class R> struct to_asio_buffers_helper<is_const, R, std::array<asio::mutable_buffer, N>, false, true>
03016     {
03017       template<class U> std::vector<R> operator()(U &v) const
03018       {
03019         std::vector<R> ret(v.begin(), v.end());
03020         return ret;
03021       }
03022     };
03023     template<bool is_const, size_t N, class R> struct to_asio_buffers_helper<is_const, R, std::array<asio::const_buffer, N>, false, true>
03024     {
03025       template<class U> std::vector<R> operator()(U &v) const
03026       {
03027         std::vector<R> ret(v.begin(), v.end());
03028         return ret;
03029       }
03030     };
03031 }
03044 template<class T> inline std::vector<asio::mutable_buffer> to_asio_buffers(T &v)
03045 {
03046   static_assert(!std::is_pointer<T>::value, "You cannot assemble scatter gather buffers from raw pointers, you need to specify a length or supply a type carrying a length");
03047   return detail::to_asio_buffers_helper<false, asio::mutable_buffer, T>()(v);
03048 }
03061 template<class T> inline std::vector<asio::const_buffer> to_asio_buffers(const T &v)
03062 {
03063   static_assert(!std::is_pointer<T>::value, "You cannot assemble scatter gather buffers from raw pointers, you need to specify a length or supply a type carrying a length");
03064   return detail::to_asio_buffers_helper<true, asio::const_buffer, T>()(v);
03065 }
03073 template<class T, size_t N> inline std::vector<asio::mutable_buffer> to_asio_buffers(T (&v)[N])
03074 {
03075   return to_asio_buffers(reinterpret_cast<std::array<T, N> &>(v));
03076 }
03084 template<class T, size_t N> inline std::vector<asio::const_buffer> to_asio_buffers(const T (&v)[N])
03085 {
03086   return to_asio_buffers(reinterpret_cast<const std::array<T, N> &>(v));
03087 }
03088 
03089 namespace detail
03090 {
03092     template<bool for_writing> class io_req_impl;
03093     template<> class io_req_impl<false>
03094     {
03095     public:
03097         future<> precondition;
03099         std::vector<asio::mutable_buffer> buffers;
03101         off_t where;
03103         io_req_impl() { }
03105         io_req_impl(const io_req_impl &o) : precondition(o.precondition), buffers(o.buffers), where(o.where) { }
03107         io_req_impl(io_req_impl &&o) noexcept : precondition(std::move(o.precondition)), buffers(std::move(o.buffers)), where(std::move(o.where)) { }
03109         io_req_impl &operator=(const io_req_impl &o) { precondition=o.precondition; buffers=o.buffers; where=o.where; return *this; }
03111         io_req_impl &operator=(io_req_impl &&o) noexcept { precondition=std::move(o.precondition); buffers=std::move(o.buffers); where=std::move(o.where); return *this; }
03113         io_req_impl(future<> _precondition, std::vector<asio::mutable_buffer> _buffers, off_t _where) : precondition(std::move(_precondition)), buffers(std::move(_buffers)), where(_where) { _validate(); }
03115         bool validate() const
03116         {
03117             //if(!precondition.validate()) return false;
03118             if(buffers.empty()) return false;
03119             for(auto &b: buffers)
03120             {
03121                 if(!asio::buffer_cast<const void *>(b) || !asio::buffer_size(b)) return false;
03122                 if(precondition.parent() && !!(precondition.parent()->fileflags(file_flags::none)&file_flags::os_direct))
03123                 {
03124                     if(((size_t) asio::buffer_cast<const void *>(b) & 4095) || (asio::buffer_size(b) & 4095)) return false;
03125                 }
03126             }
03127             return true;
03128         }
03129     private:
03130         void _validate() const
03131         {
03132 #if BOOST_AFIO_VALIDATE_INPUTS
03133             if(!validate())
03134                 BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03135 #endif
03136         }
03137     };
03138     template<> class io_req_impl<true>
03139     {
03140     public:
03142         future<> precondition;
03144         std::vector<asio::const_buffer> buffers;
03146         off_t where;
03148         io_req_impl() { }
03150         io_req_impl(const io_req_impl &o) : precondition(o.precondition), buffers(o.buffers), where(o.where) { }
03152         io_req_impl(io_req_impl &&o) noexcept : precondition(std::move(o.precondition)), buffers(std::move(o.buffers)), where(std::move(o.where)) { }
03154         io_req_impl(const io_req_impl<false> &o) : precondition(o.precondition), where(o.where) { buffers.reserve(o.buffers.capacity()); for(auto &i: o.buffers){ buffers.push_back(i); } }
03156         io_req_impl(io_req_impl<false> &&o) noexcept : precondition(std::move(o.precondition)), where(std::move(o.where)) { buffers.reserve(o.buffers.capacity()); for(auto &&i: o.buffers){ buffers.push_back(std::move(i)); } }
03158         io_req_impl &operator=(const io_req_impl &o) { precondition=o.precondition; buffers=o.buffers; where=o.where; return *this; }
03160         io_req_impl &operator=(io_req_impl &&o) noexcept { precondition=std::move(o.precondition); buffers=std::move(o.buffers); where=std::move(o.where); return *this; }
03162         io_req_impl(future<> _precondition, std::vector<asio::const_buffer> _buffers, off_t _where) : precondition(std::move(_precondition)), buffers(std::move(_buffers)), where(_where) { _validate(); }
03164         io_req_impl(future<> _precondition, std::vector<asio::mutable_buffer> _buffers, off_t _where) : precondition(std::move(_precondition)), where(_where)
03165         {
03166             buffers.reserve(_buffers.capacity());
03167             for(auto &&i: _buffers)
03168                 buffers.push_back(std::move(i));
03169             _validate();
03170         }
03172         bool validate() const
03173         {
03174             //if(!precondition.validate()) return false;
03175             if(buffers.empty()) return false;
03176             for(auto &b: buffers)
03177             {
03178                 if(!asio::buffer_cast<const void *>(b) || !asio::buffer_size(b)) return false;
03179                 if(precondition.parent() && !!(precondition.parent()->fileflags(file_flags::none)&file_flags::os_direct))
03180                 {
03181                     if(((size_t) asio::buffer_cast<const void *>(b) & 4095) || (asio::buffer_size(b) & 4095)) return false;
03182                 }
03183             }
03184             return true;
03185         }
03186     private:
03187         void _validate() const
03188         {
03189 #if BOOST_AFIO_VALIDATE_INPUTS
03190             if(!validate())
03191                 BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03192 #endif
03193         }
03194     };
03195 }
03196 
03203 template<class T> struct io_req : public detail::io_req_impl<false>
03204 {
03205 #ifdef DOXYGEN_SHOULD_SKIP_THIS
03206 
03207     future<> precondition;
03209     std::vector<asio::mutable_buffer> buffers;
03211     off_t where;
03212 #endif
03213 
03214     io_req() { }
03216     io_req(const io_req &o) : detail::io_req_impl<false>(o) { }
03218     io_req(io_req &&o) noexcept : detail::io_req_impl<false>(std::move(o)) { }
03220     io_req &operator=(const io_req &o) { static_cast<detail::io_req_impl<false>>(*this)=o; return *this; }
03222     io_req &operator=(io_req &&o) noexcept { static_cast<detail::io_req_impl<false>>(*this)=std::move(o); return *this; }
03224     io_req(future<> _precondition, T *v, size_t _length, off_t _where) : detail::io_req_impl<false>(std::move(_precondition), to_asio_buffers(v, _length), _where) { }
03226     template<class U> io_req(future<> _precondition, U &v, off_t _where) : detail::io_req_impl<false>(std::move(_precondition), to_asio_buffers(v), _where) { }
03228     template<class U, size_t N> io_req(future<> _precondition, U (&v)[N], off_t _where) : detail::io_req_impl<false>(std::move(_precondition), to_asio_buffers(v), _where) { }
03229 };
03236 template<class T> struct io_req<const T> : public detail::io_req_impl<true>
03237 {
03238 #ifdef DOXYGEN_SHOULD_SKIP_THIS
03239 
03240     future<> precondition;
03242     std::vector<asio::const_buffer> buffers;
03244     off_t where;
03245 #endif
03246 
03247     io_req() { }
03249     io_req(const io_req &o) : detail::io_req_impl<true>(o) { }
03251     io_req(io_req &&o) noexcept : detail::io_req_impl<true>(std::move(o)) { }
03253     io_req(const io_req<T> &o) : detail::io_req_impl<true>(o) { }
03255     io_req(io_req<T> &&o) noexcept : detail::io_req_impl<true>(std::move(o)) { }
03257     io_req &operator=(const io_req &o) { static_cast<detail::io_req_impl<true>>(*this)=o; return *this; }
03259     io_req &operator=(io_req &&o) noexcept { static_cast<detail::io_req_impl<true>>(*this)=std::move(o); return *this; }
03261     io_req(future<> _precondition, const T *v, size_t _length, off_t _where) : detail::io_req_impl<true>(std::move(_precondition), to_asio_buffers(v, _length), _where) { }
03263     template<class U> io_req(future<> _precondition, const U &v, off_t _where) : detail::io_req_impl<true>(std::move(_precondition), to_asio_buffers(v), _where) { }
03265     template<class U, size_t N> io_req(future<> _precondition, const U (&v)[N], off_t _where) : detail::io_req_impl<true>(std::move(_precondition), to_asio_buffers(v), _where) { }
03266 };
03271 template<> struct io_req<void> : public detail::io_req_impl<false>
03272 {
03273 #ifdef DOXYGEN_SHOULD_SKIP_THIS
03274 
03275   future<> precondition;
03277   std::vector<asio::mutable_buffer> buffers;
03279   off_t where;
03280 #endif
03281 
03282   io_req() { }
03284   io_req(const io_req &o) : detail::io_req_impl<false>(o) { }
03286   io_req(io_req &&o) noexcept : detail::io_req_impl<false>(std::move(o)) { }
03288   io_req &operator=(const io_req &o) { static_cast<detail::io_req_impl<false>>(*this)=o; return *this; }
03290   io_req &operator=(io_req &&o) noexcept { static_cast<detail::io_req_impl<false>>(*this)=std::move(o); return *this; }
03292   io_req(future<> _precondition, void *v, size_t _length, off_t _where) : detail::io_req_impl<false>(std::move(_precondition), to_asio_buffers(v, _length), _where) { }
03293 };
03298 template<> struct io_req<const void> : public detail::io_req_impl<true>
03299 {
03300 #ifdef DOXYGEN_SHOULD_SKIP_THIS
03301 
03302   future<> precondition;
03304   std::vector<asio::const_buffer> buffers;
03306   off_t where;
03307 #endif
03308 
03309   io_req() { }
03311   io_req(const io_req &o) : detail::io_req_impl<true>(o) { }
03313   io_req(io_req &&o) noexcept : detail::io_req_impl<true>(std::move(o)) { }
03315   io_req(const io_req<void> &o) : detail::io_req_impl<true>(o) { }
03317   io_req(io_req<void> &&o) noexcept : detail::io_req_impl<true>(std::move(o)) { }
03319   io_req &operator=(const io_req &o) { static_cast<detail::io_req_impl<true>>(*this)=o; return *this; }
03321   io_req &operator=(io_req &&o) noexcept { static_cast<detail::io_req_impl<true>>(*this)=std::move(o); return *this; }
03323   io_req(future<> _precondition, const void *v, size_t _length, off_t _where) : detail::io_req_impl<true>(std::move(_precondition), to_asio_buffers(v, _length), _where) { }
03324 };
03325 
03326 namespace detail
03327 {
03328   template<class T, bool is_container=detail::is_container<T>::value> struct make_io_req
03329   {
03330     typedef typename std::remove_pointer<typename std::decay<T>::type>::type _T;
03331     typedef io_req<_T> type;
03332     template<class U> type operator()(future<> _precondition, U &&v, off_t _where) const
03333     {
03334       return type(std::move(_precondition), std::forward<U>(v), _where);
03335     }
03336     template<class U> type operator()(future<> _precondition, U &&v, size_t _length, off_t _where) const
03337     {
03338       return type(std::move(_precondition), std::forward<U>(v), _length, _where);
03339     }
03340   };
03341   // If T is a container and that container's value_type is const, make sure we only create an asio::const_buffer
03342   template<class T> struct make_io_req<T, true>
03343   {
03344     typedef typename detail::is_container<T>::type container_value_type;
03345     static BOOST_CONSTEXPR_OR_CONST bool is_container_contents_const=std::is_const<container_value_type>::value || std::is_base_of<asio::const_buffer, container_value_type>::value;
03346     typedef typename std::remove_pointer<typename std::decay<T>::type>::type __T;
03347     typedef typename std::conditional<is_container_contents_const, typename std::add_const<__T>::type, __T>::type _T;
03348     typedef io_req<_T> type;
03349     template<class U> type operator()(future<> _precondition, U &&v, off_t _where) const
03350     {
03351       return type(std::move(_precondition), std::forward<U>(v), _where);
03352     }
03353     template<class U> type operator()(future<> _precondition, U &&v, size_t _length, off_t _where) const
03354     {
03355       return type(std::move(_precondition), std::forward<U>(v), _length, _where);
03356     }
03357   };
03358 }
03370 template<class T> inline auto make_io_req(future<> _precondition, T &&v, off_t _where) -> decltype(detail::make_io_req<T>()(std::move(_precondition), std::forward<T>(v), _where))
03371 {
03372   return detail::make_io_req<T>()(std::move(_precondition), std::forward<T>(v), _where);
03373 }
03385 template<class T> inline io_req<const std::initializer_list<T>> make_io_req(future<> _precondition, const std::initializer_list<T> &v, off_t _where)
03386 {
03387   return io_req<const std::initializer_list<T>>(std::move(_precondition), v, _where);
03388 }
03401 template<class T> inline auto make_io_req(future<> _precondition, T &&v, size_t _length, off_t _where) -> decltype(detail::make_io_req<T>()(std::move(_precondition), std::forward<T>(v), _length, _where))
03402 {
03403   return detail::make_io_req<T>()(std::move(_precondition), std::forward<T>(v), _length, _where);
03404 }
03405 
03406 
03420 struct enumerate_req
03421 {
03422     future<> precondition;    
03423     size_t maxitems;             
03424     bool restart;                
03425     path glob;                   
03426     metadata_flags metadata;     
03427 
03428     enum class filter
03429     {
03430       none,        
03431       fastdeleted  
03432     };
03433     filter filtering;            
03434 
03435     enumerate_req() : maxitems(0), restart(false), metadata(metadata_flags::None), filtering(filter::fastdeleted) { }
03445     enumerate_req(future<> _precondition, size_t _maxitems=2, bool _restart=true, path _glob=path(), metadata_flags _metadata=metadata_flags::None, filter _filtering=filter::fastdeleted) : precondition(std::move(_precondition)), maxitems(_maxitems), restart(_restart), glob(std::move(_glob)), metadata(_metadata), filtering(_filtering) { _validate(); }
03455     enumerate_req(future<> _precondition, path _glob, size_t _maxitems=2, bool _restart=true, metadata_flags _metadata=metadata_flags::None, filter _filtering=filter::fastdeleted) : precondition(std::move(_precondition)), maxitems(_maxitems), restart(_restart), glob(std::move(_glob)), metadata(_metadata), filtering(_filtering) { _validate(); }
03465     enumerate_req(future<> _precondition, metadata_flags _metadata, size_t _maxitems=2, bool _restart=true, path _glob=path(), filter _filtering=filter::fastdeleted) : precondition(std::move(_precondition)), maxitems(_maxitems), restart(_restart), glob(std::move(_glob)), metadata(_metadata), filtering(_filtering) { _validate(); }
03467     bool validate() const
03468     {
03469         if(!maxitems) return false;
03470         return !precondition.valid() || precondition.validate();
03471     }
03472 private:
03473     void _validate() const
03474     {
03475 #if BOOST_AFIO_VALIDATE_INPUTS
03476         if(!validate())
03477             BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03478 #endif
03479     }
03480 };
03481 
03482 // Undocumented deliberately
03483 struct lock_req
03484 {
03485   future<> precondition;
03486   enum class Type { unknown, read_lock, write_lock, unlock } type;
03487   off_t offset, length;
03488   //chrono::time_point<chrono::steady_clock> deadline;
03489   lock_req() : type(Type::unknown), offset(0), length(0) { }
03490   lock_req(future<> _precondition, Type _type=Type::write_lock) : precondition(_precondition), type(_type), offset(0), length((off_t)-1) { _validate(); }
03491   lock_req(future<> _precondition, std::nullptr_t) : precondition(_precondition), type(Type::unlock), offset(0), length((off_t)-1) { _validate(); }
03492   lock_req(future<> _precondition, Type _type, off_t _offset, off_t _length) : precondition(_precondition), type(_type), offset(_offset), length(_length) { _validate(); }
03493   lock_req(future<> _precondition, off_t _offset, off_t _length, Type _type=Type::write_lock) : precondition(_precondition), type(_type), offset(_offset), length(_length) { _validate(); }
03495   bool validate() const
03496   {
03497       if(type==Type::unknown) return false;
03498       if(offset+length<offset) return false;
03499       return !precondition.valid() || precondition.validate();
03500   }
03501 private:
03502   void _validate() const
03503   {
03504 #if BOOST_AFIO_VALIDATE_INPUTS
03505       if(!validate())
03506           BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03507 #endif
03508   }
03509 };
03510 
03511 
03512 
03513 namespace detail {
03514     template<bool iswrite, class T> struct async_file_io_dispatcher_rwconverter
03515     {
03516         typedef detail::io_req_impl<iswrite> return_type;
03517         const std::vector<return_type> &operator()(const std::vector<io_req<T>> &ops) const
03518         {
03519             typedef io_req<T> reqT;
03520             static_assert(std::is_convertible<reqT, return_type>::value, "io_req<T> is not convertible to detail::io_req_impl<constness>");
03521             static_assert(sizeof(return_type)==sizeof(reqT), "io_req<T> does not have the same size as detail::io_req_impl<constness>");
03522             return reinterpret_cast<const std::vector<return_type> &>(ops);
03523         }
03524     };
03525 }
03526 
03527 #if defined(BOOST_AFIO_ENABLE_BENCHMARKING_COMPLETION) // Only really used for benchmarking
03528 inline future<> dispatcher::completion(const future<> &req, const std::pair<async_op_flags, dispatcher::completion_t *> &callback)
03529 {
03530     std::vector<future<>> r;
03531     std::vector<std::pair<async_op_flags, dispatcher::completion_t *>> i;
03532     r.reserve(1); i.reserve(1);
03533     r.push_back(req);
03534     i.push_back(callback);
03535     auto ret(std::move(completion(r, i).front()));
03536     return ret;
03537 }
03538 #endif
03539 inline future<> dispatcher::completion(const future<> &req, const std::pair<async_op_flags, std::function<dispatcher::completion_t>> &callback)
03540 {
03541     std::vector<future<>> r;
03542     std::vector<std::pair<async_op_flags, std::function<dispatcher::completion_t>>> i;
03543     r.reserve(1); i.reserve(1);
03544     r.push_back(req);
03545     i.push_back(callback);
03546     auto ret(std::move(completion(r, i).front()));
03547     return ret;
03548 }
03549 namespace detail {
03550     template<class tasktype> std::pair<bool, handle_ptr> doCall(size_t, future<> _, std::shared_ptr<tasktype> c)
03551     {
03552         (*c)();
03553         return std::make_pair(true, _.get_handle(true));
03554     }
03555 }
03556 template<class R> inline std::vector<future<R>> dispatcher::call(const std::vector<future<>> &ops, const std::vector<std::function<R()>> &callables)
03557 {
03558     typedef packaged_task<R()> tasktype;
03559     std::vector<stl_future<R>> retfutures;
03560     std::vector<std::pair<async_op_flags, std::function<completion_t>>> callbacks;
03561     retfutures.reserve(callables.size());
03562     callbacks.reserve(callables.size());
03563     
03564     for(auto &t: callables)
03565     {
03566         std::shared_ptr<tasktype> c(std::make_shared<tasktype>(std::function<R()>(t)));
03567         retfutures.push_back(c->get_future());
03568         callbacks.push_back(std::make_pair(async_op_flags::none, std::bind(&detail::doCall<tasktype>, std::placeholders::_1, std::placeholders::_2, std::move(c))));
03569     }
03570     auto _ret(completion(ops, callbacks));
03571     std::vector<future<R>> ret;
03572     ret.reserve(_ret.size());
03573     for (size_t n = 0; n < _ret.size(); n++)
03574       ret.push_back(future<R>(std::move(_ret[n]), std::move(retfutures[n])));
03575     return ret;
03576 }
03577 template<class R> inline future<R> dispatcher::call(const future<> &req, std::function<R()> callback)
03578 {
03579     std::vector<future<>> i;
03580     std::vector<std::function<R()>> c;
03581     i.reserve(1); c.reserve(1);
03582     i.push_back(req);
03583     c.push_back(std::move(callback));
03584     auto ret(std::move(call(i, c).front()));
03585     return ret;
03586 }
03587 
03588 #ifndef DOXYGEN_SHOULD_SKIP_THIS
03589 template<class C, class... Args> inline future<typename detail::vs2013_variadic_overload_resolution_workaround<C, Args...>::type> dispatcher::call(const future<> &req, C callback, Args... args)
03590 #else
03591 template<class C, class... Args> inline future<typename std::result_of<C(Args...)>::type> dispatcher::call(const future<> &req, C callback, Args... args)
03592 #endif
03593 {
03594     typedef typename std::result_of<C(Args...)>::type rettype;
03595     return call(req, std::function<rettype()>(std::bind<rettype>(callback, args...)));
03596 }
03597 
03598 inline future<> dispatcher::adopt(handle_ptr h)
03599 {
03600     std::vector<handle_ptr> i;
03601     i.reserve(1);
03602     i.push_back(std::move(h));
03603     auto ret(std::move(adopt(i).front()));
03604     return ret;
03605 }
03606 inline future<> dispatcher::dir(const path_req &req)
03607 {
03608     std::vector<path_req> i;
03609     i.reserve(1);
03610     i.push_back(req);
03611     auto ret(std::move(dir(i).front()));
03612     return ret;
03613 }
03614 inline future<> dispatcher::rmdir(const path_req &req)
03615 {
03616     std::vector<path_req> i;
03617     i.reserve(1);
03618     i.push_back(req);
03619     auto ret(std::move(rmdir(i).front()));
03620     return ret;
03621 }
03622 inline future<> dispatcher::file(const path_req &req)
03623 {
03624     std::vector<path_req> i;
03625     i.reserve(1);
03626     i.push_back(req);
03627     auto ret(std::move(file(i).front()));
03628     return ret;
03629 }
03630 inline future<> dispatcher::rmfile(const path_req &req)
03631 {
03632     std::vector<path_req> i;
03633     i.reserve(1);
03634     i.push_back(req);
03635     auto ret(std::move(rmfile(i).front()));
03636     return ret;
03637 }
03638 inline future<> dispatcher::symlink(const path_req &req, const future<> &target)
03639 {
03640     std::vector<path_req> i(1, req);
03641     std::vector<future<>> t(1, target);
03642     auto ret(std::move(symlink(i, t).front()));
03643     return ret;
03644 }
03645 inline future<> dispatcher::rmsymlink(const path_req &req)
03646 {
03647     std::vector<path_req> i;
03648     i.reserve(1);
03649     i.push_back(req);
03650     auto ret(std::move(rmsymlink(i).front()));
03651     return ret;
03652 }
03653 inline future<> dispatcher::sync(const future<> &req)
03654 {
03655     std::vector<future<>> i;
03656     i.reserve(1);
03657     i.push_back(req);
03658     auto ret(std::move(sync(i).front()));
03659     return ret;
03660 }
03661 inline future<> dispatcher::zero(const future<> &req, const std::vector<std::pair<off_t, off_t>> &ranges)
03662 {
03663     std::vector<future<>> i;
03664     std::vector<std::vector<std::pair<off_t, off_t>>> r;
03665     i.reserve(1);
03666     i.push_back(req);
03667     r.reserve(1);
03668     r.push_back(ranges);
03669     auto ret(std::move(zero(i, r).front()));
03670     return ret;
03671 }
03672 inline future<> dispatcher::close(const future<> &req)
03673 {
03674     std::vector<future<>> i;
03675     i.reserve(1);
03676     i.push_back(req);
03677     auto ret(std::move(close(i).front()));
03678     return ret;
03679 }
03680 #ifndef DOXYGEN_SHOULD_SKIP_THIS
03681 inline future<> dispatcher::read(const detail::io_req_impl<false> &req)
03682 {
03683     std::vector<detail::io_req_impl<false>> i;
03684     i.reserve(1);
03685     i.push_back(req);
03686     auto ret(std::move(read(i).front()));
03687     return ret;
03688 }
03689 inline future<> dispatcher::write(const detail::io_req_impl<true> &req)
03690 {
03691     std::vector<detail::io_req_impl<true>> i;
03692     i.reserve(1);
03693     i.push_back(req);
03694     auto ret(std::move(write(i).front()));
03695     return ret;
03696 }
03697 #endif
03698 template<class T> inline std::vector<future<>> dispatcher::read(const std::vector<io_req<T>> &ops)
03699 {
03700     return read(detail::async_file_io_dispatcher_rwconverter<false, T>()(ops));
03701 }
03702 template<class T> inline std::vector<future<>> dispatcher::write(const std::vector<io_req<T>> &ops)
03703 {
03704     return write(detail::async_file_io_dispatcher_rwconverter<true, T>()(ops));
03705 }
03706 inline future<> dispatcher::truncate(const future<> &op, off_t newsize)
03707 {
03708     std::vector<future<>> o;
03709     std::vector<off_t> i;
03710     o.reserve(1);
03711     o.push_back(op);
03712     i.reserve(1);
03713     i.push_back(newsize);
03714     auto ret(std::move(truncate(o, i).front()));
03715     return ret;
03716 }
03717 inline future<std::pair<std::vector<directory_entry>, bool>> dispatcher::enumerate(const enumerate_req &req)
03718 {
03719     std::vector<enumerate_req> i;
03720     i.reserve(1);
03721     i.push_back(req);
03722     auto ret(std::move(enumerate(i).front()));
03723     return ret;
03724 }
03725 inline future<std::vector<std::pair<off_t, off_t>>> dispatcher::extents(const future<> &op)
03726 {
03727     std::vector<future<>> o;
03728     o.reserve(1);
03729     o.push_back(op);
03730     auto ret(std::move(extents(o).front()));
03731     return ret;
03732 }
03733 inline future<statfs_t> dispatcher::statfs(const future<> &op, const fs_metadata_flags &req)
03734 {
03735   std::vector<future<>> o;
03736   std::vector<fs_metadata_flags> i;
03737   o.reserve(1);
03738   o.push_back(op);
03739   i.reserve(1);
03740   i.push_back(req);
03741   auto ret(std::move(statfs(o, i).front()));
03742   return ret;
03743 }
03744 inline future<> dispatcher::depends(future<> precondition, future<> op)
03745 {
03746     std::pair<async_op_flags, std::function<dispatcher::completion_t>> callback(std::make_pair(async_op_flags::immediate,
03747     [BOOST_AFIO_LAMBDA_MOVE_CAPTURE(op)](size_t, future<>) { return std::make_pair(true, op.get_handle()); }));
03748     std::vector<future<>> r;
03749     std::vector<std::pair<async_op_flags, std::function<dispatcher::completion_t>>> i;
03750     r.reserve(1); i.reserve(1);
03751     r.push_back(precondition);
03752     i.push_back(std::move(callback));
03753     auto ret(std::move(completion(r, i).front()));
03754     return ret;
03755 }
03756 
03757 namespace detail
03758 {
03759   template<class T> struct async_dir
03760   {
03761     T path;
03762     file_flags flags;
03763     async_dir(T _path, file_flags _flags) : path(std::move(_path)), flags(_flags) { }
03764     future<> operator()(future<> f=future<>())
03765     {
03766       dispatcher *dispatcher = f.parent();
03767       path_req req(!dispatcher ? (
03768         dispatcher = current_dispatcher().get(),
03769         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03770         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03771 #if BOOST_AFIO_VALIDATE_INPUTS
03772       if (!req.validate())
03773         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03774 #endif
03775       auto ret(std::move(dispatcher->dir(std::vector<path_req>(1, std::move(req))).front()));
03776       return ret;
03777     }
03778   };
03779   template<class T> struct async_rmdir
03780   {
03781     T path;
03782     file_flags flags;
03783     async_rmdir(T _path, file_flags _flags) : path(std::move(_path)), flags(_flags) { }
03784     future<> operator()(future<> f = future<>())
03785     {
03786       dispatcher *dispatcher = f.parent();
03787       path_req req(!dispatcher ? (
03788         dispatcher = current_dispatcher().get(),
03789         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03790         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03791 #if BOOST_AFIO_VALIDATE_INPUTS
03792       if (!req.validate())
03793         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03794 #endif
03795       auto ret(std::move(dispatcher->rmdir(std::vector<path_req>(1, std::move(req))).front()));
03796       return ret;
03797     }
03798   };
03799   template<class T> struct async_file
03800   {
03801     T path;
03802     file_flags flags;
03803     async_file(T _path, file_flags _flags) : path(std::move(_path)), flags(_flags) { }
03804     future<> operator()(future<> f = future<>())
03805     {
03806       dispatcher *dispatcher = f.parent();
03807       path_req req(!dispatcher ? (
03808         dispatcher = current_dispatcher().get(),
03809         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03810         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03811 #if BOOST_AFIO_VALIDATE_INPUTS
03812       if (!req.validate())
03813         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03814 #endif
03815       auto ret(std::move(dispatcher->file(std::vector<path_req>(1, std::move(req))).front()));
03816       return ret;
03817     }
03818   };
03819   template<class T> struct async_rmfile
03820   {
03821     T path;
03822     file_flags flags;
03823     async_rmfile(T _path, file_flags _flags) : path(std::move(_path)), flags(_flags) { }
03824     future<> operator()(future<> f = future<>())
03825     {
03826       dispatcher *dispatcher = f.parent();
03827       path_req req(!dispatcher ? (
03828         dispatcher = current_dispatcher().get(),
03829         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03830         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03831 #if BOOST_AFIO_VALIDATE_INPUTS
03832       if (!req.validate())
03833         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03834 #endif
03835       auto ret(std::move(dispatcher->rmfile(std::vector<path_req>(1, std::move(req))).front()));
03836       return ret;
03837     }
03838   };
03839   template<class T> struct async_symlink
03840   {
03841     T path;
03842     file_flags flags;
03843     future<> target;
03844     async_symlink(T _path, file_flags _flags, future<> _target) : path(std::move(_path)), flags(_flags), target(std::move(_target)) { }
03845     future<> operator()(future<> f = future<>())
03846     {
03847       dispatcher *dispatcher = f.parent();
03848       path_req req(!dispatcher ? (
03849         dispatcher = current_dispatcher().get(),
03850         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03851         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03852 #if BOOST_AFIO_VALIDATE_INPUTS
03853       if (!req.validate())
03854         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03855 #endif
03856       auto ret(std::move(dispatcher->symlink(std::vector<path_req>(1, std::move(req)), std::vector<future<>>(1, std::move(target))).front()));
03857       return ret;
03858     }
03859   };
03860   template<class T> struct async_rmsymlink
03861   {
03862     T path;
03863     file_flags flags;
03864     async_rmsymlink(T _path, file_flags _flags) : path(std::move(_path)), flags(_flags) { }
03865     future<> operator()(future<> f = future<>())
03866     {
03867       dispatcher *dispatcher = f.parent();
03868       path_req req(!dispatcher ? (
03869         dispatcher = current_dispatcher().get(),
03870         path_req(path_req::absolute(std::move(f), std::move(path), std::move(flags)))
03871         ) : path_req(path_req::relative(std::move(f), std::move(path), std::move(flags))));
03872 #if BOOST_AFIO_VALIDATE_INPUTS
03873       if (!req.validate())
03874         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03875 #endif
03876       auto ret(std::move(dispatcher->rmsymlink(std::vector<path_req>(1, std::move(req))).front()));
03877       return ret;
03878     }
03879   };
03880   struct async_sync
03881   {
03882     future<> operator()(future<> f = future<>())
03883     {
03884       dispatcher *dispatcher = f.parent();
03885       if (!dispatcher)
03886         dispatcher = current_dispatcher().get();
03887       auto ret(std::move(dispatcher->sync(std::vector<future<>>(1, std::move(f))).front()));
03888       return ret;
03889     }
03890   };
03891   struct async_close
03892   {
03893     future<> operator()(future<> f = future<>())
03894     {
03895       dispatcher *dispatcher = f.parent();
03896       if (!dispatcher)
03897         dispatcher = current_dispatcher().get();
03898       auto ret(std::move(dispatcher->close(std::vector<future<>>(1, std::move(f))).front()));
03899       return ret;
03900     }
03901   };
03902   struct async_read
03903   {
03904     io_req_impl<false> req;
03905     template<class U> async_read(U &&v, off_t _where) : req(BOOST_AFIO_V2_NAMESPACE::make_io_req(future<>(), std::forward<U>(v), _where)) { }
03906     template<class U> async_read(U &&v, size_t _length, off_t _where) : req(BOOST_AFIO_V2_NAMESPACE::make_io_req(future<>(), std::forward<U>(v), _length, _where)) { }
03907     future<> operator()(future<> f = future<>())
03908     {
03909       dispatcher *dispatcher = f.parent();
03910       if (!dispatcher)
03911         dispatcher = current_dispatcher().get();
03912       req.precondition = f;
03913 #if BOOST_AFIO_VALIDATE_INPUTS
03914       if (!req.validate())
03915         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03916 #endif
03917       auto ret(std::move(dispatcher->read(std::vector<io_req_impl<false>>(1, std::move(req))).front()));
03918       return ret;
03919     }
03920   };
03921   struct async_write
03922   {
03923     io_req_impl<true> req;
03924     template<class U> async_write(U &&v, off_t _where) : req(BOOST_AFIO_V2_NAMESPACE::make_io_req(future<>(), std::forward<U>(v), _where)) { }
03925     template<class U> async_write(U &&v, size_t _length, off_t _where) : req(BOOST_AFIO_V2_NAMESPACE::make_io_req(future<>(), std::forward<U>(v), _length, _where)) { }
03926     future<> operator()(future<> f = future<>())
03927     {
03928       dispatcher *dispatcher = f.parent();
03929       if (!dispatcher)
03930         dispatcher = current_dispatcher().get();
03931       req.precondition = f;
03932 #if BOOST_AFIO_VALIDATE_INPUTS
03933       if (!req.validate())
03934         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03935 #endif
03936       auto ret(std::move(dispatcher->write(std::vector<io_req_impl<true>>(1, std::move(req))).front()));
03937       return ret;
03938     }
03939   };
03940   struct async_truncate
03941   {
03942     off_t _size;
03943     async_truncate(off_t size) : _size(size) { }
03944     future<> operator()(future<> f = future<>())
03945     {
03946       dispatcher *dispatcher = f.parent();
03947       if (!dispatcher)
03948         dispatcher = current_dispatcher().get();
03949       auto ret(std::move(dispatcher->truncate(std::vector<future<>>(1, std::move(f)), std::vector<off_t>(1, _size)).front()));
03950       return ret;
03951     }
03952   };
03953   struct async_enumerate
03954   {
03955     size_t maxitems;
03956     bool restart;
03957     path glob;
03958     metadata_flags metadata;
03959     enumerate_req::filter filtering;
03960     async_enumerate(size_t _maxitems, bool _restart, path _glob, metadata_flags _metadata, enumerate_req::filter _filtering) : maxitems(_maxitems), restart(_restart), glob(_glob), metadata(_metadata), filtering(_filtering) { }
03961     future<std::pair<std::vector<directory_entry>, bool>> operator()(future<> f = future<>())
03962     {
03963       enumerate_req req(std::move(f), maxitems, restart, std::move(glob), metadata, filtering);
03964       dispatcher *dispatcher = f.parent();
03965       if (!dispatcher)
03966         dispatcher = current_dispatcher().get();
03967 #if BOOST_AFIO_VALIDATE_INPUTS
03968       if (!req.validate())
03969         BOOST_AFIO_THROW(std::invalid_argument("Inputs are invalid."));
03970 #endif
03971       auto ret(std::move(dispatcher->enumerate(std::vector<enumerate_req>(1, std::move(req))).front()));
03972       return ret;
03973     }
03974   };
03975   struct async_zero
03976   {
03977     std::vector<std::pair<off_t, off_t>> ranges;
03978     async_zero(std::vector<std::pair<off_t, off_t>> _ranges) : ranges(_ranges) { }
03979     future<> operator()(future<> f = future<>())
03980     {
03981       dispatcher *dispatcher = f.parent();
03982       if (!dispatcher)
03983         dispatcher = current_dispatcher().get();
03984       auto ret(std::move(dispatcher->zero(std::vector<future<>>(1, std::move(f)), std::vector<std::vector<std::pair<off_t, off_t>>>(1, std::move(ranges))).front()));
03985       return ret;
03986     }
03987   };
03988   struct async_extents
03989   {
03990     future<std::vector<std::pair<off_t, off_t>>> operator()(future<> f = future<>())
03991     {
03992       dispatcher *dispatcher = f.parent();
03993       if (!dispatcher)
03994         dispatcher = current_dispatcher().get();
03995       auto ret(std::move(dispatcher->extents(std::vector<future<>>(1, std::move(f))).front()));
03996       return ret;
03997     }
03998   };
03999   struct async_statfs
04000   {
04001     fs_metadata_flags req;
04002     async_statfs(fs_metadata_flags _req) : req(_req) { }
04003     future<statfs_t> operator()(future<> f = future<>())
04004     {
04005       dispatcher *dispatcher = f.parent();
04006       if (!dispatcher)
04007         dispatcher = current_dispatcher().get();
04008       auto ret(std::move(dispatcher->statfs(std::vector<future<>>(1, std::move(f)), std::vector<fs_metadata_flags>(1, req)).front()));
04009       return ret;
04010     }
04011   };
04012   template<class T> struct _is_not_handle : public std::true_type { };
04013   template<class T> struct _is_not_handle<future<T>> : public std::false_type { };
04014   template<> struct _is_not_handle<handle_ptr> : public std::false_type { };
04015   template<class T> struct is_not_handle : public _is_not_handle<typename std::decay<T>::type> { };
04016 }
04017 
04037 template<class T> inline future<> async_dir(future<> _precondition, T _path, file_flags _flags = file_flags::none)
04038 {
04039   return detail::async_dir<T>(std::move(_path), _flags)(std::move(_precondition));
04040 }
04059 template<class T, typename=typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_dir(T _path, file_flags _flags = file_flags::none)
04060 {
04061   return detail::async_dir<T>(std::move(_path), _flags)(future<>());
04062 }
04082 template<class T> inline handle_ptr dir(future<> _precondition, T _path, file_flags _flags = file_flags::none)
04083 {
04084   return detail::async_dir<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle();
04085 }
04104 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr dir(T _path, file_flags _flags = file_flags::none)
04105 {
04106   return detail::async_dir<T>(std::move(_path), _flags)(future<>()).get_handle();
04107 }
04128 template<class T> inline handle_ptr dir(error_code &_ec, future<> _precondition, T _path, file_flags _flags = file_flags::none)
04129 {
04130   return detail::async_dir<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle(_ec);
04131 }
04151 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr dir(error_code &_ec, T _path, file_flags _flags = file_flags::none)
04152 {
04153   return detail::async_dir<T>(std::move(_path), _flags)(future<>()).get_handle(_ec);
04154 }
04155 
04177 template<class T=path> inline future<> async_rmdir(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04178 {
04179   return detail::async_rmdir<T>(std::move(_path), _flags)(std::move(_precondition));
04180 }
04199 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_rmdir(T _path, file_flags _flags = file_flags::none)
04200 {
04201   return detail::async_rmdir<T>(std::move(_path), _flags)(future<>());
04202 }
04223 template<class T=path> inline void rmdir(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04224 {
04225   detail::async_rmdir<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle();
04226 }
04244 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmdir(T _path, file_flags _flags = file_flags::none)
04245 {
04246   detail::async_rmdir<T>(std::move(_path), _flags)(future<>()).get_handle();
04247 }
04269 template<class T=path> inline void rmdir(error_code &_ec, future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04270 {
04271   detail::async_rmdir<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle(_ec);
04272 }
04291 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmdir(error_code &_ec, T _path, file_flags _flags = file_flags::none)
04292 {
04293   detail::async_rmdir<T>(std::move(_path), _flags)(future<>()).get_handle(_ec);
04294 }
04295 
04316 template<class T> inline future<> async_file(future<> _precondition, T _path, file_flags _flags = file_flags::none)
04317 {
04318   return detail::async_file<T>(std::move(_path), _flags)(std::move(_precondition));
04319 }
04338 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_file(T _path, file_flags _flags = file_flags::none)
04339 {
04340   return detail::async_file<T>(std::move(_path), _flags)(future<>());
04341 }
04362 template<class T> inline handle_ptr file(future<> _precondition, T _path, file_flags _flags = file_flags::none)
04363 {
04364   return detail::async_file<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle();
04365 }
04384 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr file(T _path, file_flags _flags = file_flags::none)
04385 {
04386   return detail::async_file<T>(std::move(_path), _flags)(future<>()).get_handle();
04387 }
04409 template<class T> inline handle_ptr file(error_code &_ec, future<> _precondition, T _path, file_flags _flags = file_flags::none)
04410 {
04411   return detail::async_file<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle(_ec);
04412 }
04432 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr file(error_code &_ec, T _path, file_flags _flags = file_flags::none)
04433 {
04434   return detail::async_file<T>(std::move(_path), _flags)(future<>()).get_handle(_ec);
04435 }
04436 
04458 template<class T=path> inline future<> async_rmfile(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04459 {
04460   return detail::async_rmfile<T>(std::move(_path), _flags)(std::move(_precondition));
04461 }
04480 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_rmfile(T _path, file_flags _flags = file_flags::none)
04481 {
04482   return detail::async_rmfile<T>(std::move(_path), _flags)(future<>());
04483 }
04504 template<class T=path> inline void rmfile(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04505 {
04506   detail::async_rmfile<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle();
04507 }
04525 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmfile(T _path, file_flags _flags = file_flags::none)
04526 {
04527   detail::async_rmfile<T>(std::move(_path), _flags)(future<>()).get_handle();
04528 }
04550 template<class T=path> inline void rmfile(error_code &_ec, future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04551 {
04552   detail::async_rmfile<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle(_ec);
04553 }
04572 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmfile(error_code &_ec, T _path, file_flags _flags = file_flags::none)
04573 {
04574   detail::async_rmfile<T>(std::move(_path), _flags)(future<>()).get_handle(_ec);
04575 }
04576 
04577 
04599 template<class T> inline future<> async_symlink(future<> _precondition, T _path, future<> _target=future<>(), file_flags _flags = file_flags::none)
04600 {
04601   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(std::move(_precondition));
04602 }
04622 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_symlink(T _path, future<> _target=future<>(), file_flags _flags = file_flags::none)
04623 {
04624   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(future<>());
04625 }
04647 template<class T> inline handle_ptr symlink(future<> _precondition, T _path, future<> _target = future<>(), file_flags _flags = file_flags::none)
04648 {
04649   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(std::move(_precondition)).get_handle();
04650 }
04670 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr symlink(T _path, future<> _target = future<>(), file_flags _flags = file_flags::none)
04671 {
04672   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(future<>()).get_handle();
04673 }
04696 template<class T> inline handle_ptr symlink(error_code &_ec, future<> _precondition, T _path, future<> _target = future<>(), file_flags _flags = file_flags::none)
04697 {
04698   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(std::move(_precondition)).get_handle(_ec);
04699 }
04720 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline handle_ptr symlink(error_code &_ec, T _path, future<> _target = future<>(), file_flags _flags = file_flags::none)
04721 {
04722   return detail::async_symlink<T>(std::move(_path), _flags, std::move(_target))(future<>()).get_handle(_ec);
04723 }
04724 
04746 template<class T=path> inline future<> async_rmsymlink(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04747 {
04748   return detail::async_rmsymlink<T>(std::move(_path), _flags)(std::move(_precondition));
04749 }
04768 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline future<> async_rmsymlink(T _path, file_flags _flags = file_flags::none)
04769 {
04770   return detail::async_rmsymlink<T>(std::move(_path), _flags)(future<>());
04771 }
04792 template<class T=path> inline void rmsymlink(future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04793 {
04794   detail::async_rmsymlink<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle();
04795 }
04813 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmsymlink(T _path, file_flags _flags = file_flags::none)
04814 {
04815   detail::async_rmsymlink<T>(std::move(_path), _flags)(future<>()).get_handle();
04816 }
04838 template<class T=path> inline void rmsymlink(error_code &_ec, future<> _precondition, T _path = path(), file_flags _flags = file_flags::none)
04839 {
04840   detail::async_rmsymlink<T>(std::move(_path), _flags)(std::move(_precondition)).get_handle(_ec);
04841 }
04860 template<class T, typename = typename std::enable_if<detail::is_not_handle<T>::value>::type> inline void rmsymlink(error_code &_ec, T _path, file_flags _flags = file_flags::none)
04861 {
04862   detail::async_rmsymlink<T>(std::move(_path), _flags)(future<>()).get_handle(_ec);
04863 }
04864 
04865 
04877 inline future<> async_sync(future<> _precondition)
04878 {
04879   return detail::async_sync()(std::move(_precondition));
04880 }
04892 inline void sync(future<> _precondition)
04893 {
04894   detail::async_sync()(std::move(_precondition)).get_handle();
04895 }
04907 inline void sync(error_code &_ec, future<> _precondition)
04908 {
04909   detail::async_sync()(std::move(_precondition)).get_handle(_ec);
04910 }
04911 
04912 
04925 inline future<> async_zero(future<> _precondition, std::vector<std::pair<off_t, off_t>> ranges)
04926 {
04927   return detail::async_zero(std::move(ranges))(std::move(_precondition));
04928 }
04941 inline void zero(future<> _precondition, std::vector<std::pair<off_t, off_t>> ranges)
04942 {
04943   detail::async_zero(std::move(ranges))(std::move(_precondition)).get_handle();
04944 }
04958 inline void zero(error_code &_ec, future<> _precondition, std::vector<std::pair<off_t, off_t>> ranges)
04959 {
04960   detail::async_zero(std::move(ranges))(std::move(_precondition)).get_handle(_ec);
04961 }
04962 
04963 
04975 inline future<> async_close(future<> _precondition)
04976 {
04977   return detail::async_close()(std::move(_precondition));
04978 }
04990 inline void close(future<> _precondition)
04991 {
04992   detail::async_close()(std::move(_precondition)).get_handle();
04993 }
05006 inline void close(error_code &_ec, future<> _precondition)
05007 {
05008   detail::async_close()(std::move(_precondition)).get_handle(_ec);
05009 }
05010 
05011 
05028 template<class T> inline future<> async_read(future<> _precondition, T &&v, off_t _where)
05029 {
05030   return detail::async_read(std::forward<T>(v), _where)(std::move(_precondition));
05031 }
05049 template<class T> inline future<> async_read(future<> _precondition, T &&v, size_t _length, off_t _where)
05050 {
05051   return detail::async_read(std::forward<T>(v), _length, _where)(std::move(_precondition));
05052 }
05068 template<class T> inline void read(future<> _precondition, T &&v, off_t _where)
05069 {
05070   detail::async_read(std::forward<T>(v), _where)(std::move(_precondition)).get_handle();
05071 }
05088 template<class T> inline void read(future<> _precondition, T &&v, size_t _length, off_t _where)
05089 {
05090   detail::async_read(std::forward<T>(v), _length, _where)(std::move(_precondition)).get_handle();
05091 }
05108 template<class T> inline void read(error_code &_ec, future<> _precondition, T &&v, off_t _where)
05109 {
05110   detail::async_read(std::forward<T>(v), _where)(std::move(_precondition)).get_handle(_ec);
05111 }
05129 template<class T> inline void read(error_code &_ec, future<> _precondition, T &&v, size_t _length, off_t _where)
05130 {
05131   detail::async_read(std::forward<T>(v), _length, _where)(std::move(_precondition)).get_handle(_ec);
05132 }
05133 
05134 
05151 template<class T> inline future<> async_write(future<> _precondition, T &&v, off_t _where)
05152 {
05153   return detail::async_write(std::forward<T>(v), _where)(std::move(_precondition));
05154 }
05172 template<class T> inline future<> async_write(future<> _precondition, T &&v, size_t _length, off_t _where)
05173 {
05174   return detail::async_write(std::forward<T>(v), _length, _where)(std::move(_precondition));
05175 }
05191 template<class T> inline void write(future<> _precondition, T &&v, off_t _where)
05192 {
05193   detail::async_write(std::forward<T>(v), _where)(std::move(_precondition)).get_handle();
05194 }
05211 template<class T> inline void write(future<> _precondition, T &&v, size_t _length, off_t _where)
05212 {
05213   detail::async_write(std::forward<T>(v), _length, _where)(std::move(_precondition)).get_handle();
05214 }
05231 template<class T> inline void write(error_code &_ec, future<> _precondition, T &&v, off_t _where)
05232 {
05233   detail::async_write(std::forward<T>(v), _where)(std::move(_precondition)).get_handle(_ec);
05234 }
05252 template<class T> inline void write(error_code &_ec, future<> _precondition, T &&v, size_t _length, off_t _where)
05253 {
05254   detail::async_write(std::forward<T>(v), _length, _where)(std::move(_precondition)).get_handle(_ec);
05255 }
05256 
05257 
05270 inline future<> async_truncate(future<> _precondition, off_t newsize)
05271 {
05272   return detail::async_truncate(newsize)(std::move(_precondition));
05273 }
05286 inline void truncate(future<> _precondition, off_t newsize)
05287 {
05288   auto h=detail::async_truncate(newsize)(std::move(_precondition)).get_handle();
05289 }
05303 inline void truncate(error_code &_ec, future<> _precondition, off_t newsize)
05304 {
05305   auto h=detail::async_truncate(newsize)(std::move(_precondition)).get_handle(_ec);
05306 }
05307 
05308 
05333 inline future<std::pair<std::vector<directory_entry>, bool>> async_enumerate(future<> _precondition, size_t _maxitems = 2, bool _restart = true, path _glob = path(),
05334   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05335 {
05336   return detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition));
05337 }
05362 inline std::pair<std::vector<directory_entry>, bool> enumerate(future<> _precondition, size_t _maxitems = 2, bool _restart = true, path _glob = path(),
05363   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05364 {
05365   return detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition)).get();
05366 }
05392 inline std::pair<std::vector<directory_entry>, bool> enumerate(error_code &_ec, future<> _precondition, size_t _maxitems = 2, bool _restart = true, path _glob = path(),
05393   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05394 {
05395   auto ret= detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition));
05396   if(!(_ec=ret.get_error()))
05397     return ret.get();
05398   return std::pair<std::vector<directory_entry>, bool>();
05399 }
05424 inline future<std::pair<std::vector<directory_entry>, bool>> async_enumerate(future<> _precondition, path _glob, size_t _maxitems = 2, bool _restart = true,
05425   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05426 {
05427   return detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition));
05428 }
05453 inline std::pair<std::vector<directory_entry>, bool> enumerate(future<> _precondition, path _glob, size_t _maxitems = 2, bool _restart = true,
05454   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05455 {
05456   return detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition)).get();
05457 }
05483 inline std::pair<std::vector<directory_entry>, bool> enumerate(error_code &_ec, future<> _precondition, path _glob, size_t _maxitems = 2, bool _restart = true,
05484   metadata_flags _metadata = metadata_flags::None, enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05485 {
05486   auto ret = detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition));
05487   if (!(_ec = ret.get_error()))
05488     return ret.get();
05489   return std::pair<std::vector<directory_entry>, bool>();
05490 }
05515 inline future<std::pair<std::vector<directory_entry>, bool>> async_enumerate(future<> _precondition, metadata_flags _metadata, size_t _maxitems = 2, bool _restart = true,
05516   path _glob = path(), enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05517 {
05518   return detail::async_enumerate(_maxitems, _restart, _glob, _metadata, _filtering)(std::move(_precondition));
05519 }
05544 inline std::pair<std::vector<directory_entry>, bool> enumerate(future<> _precondition, metadata_flags _metadata, size_t _maxitems = 2,
05545   bool _restart = true, path _glob = path(), enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05546 {
05547   return detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition)).get();
05548 }
05574 inline std::pair<std::vector<directory_entry>, bool> enumerate(error_code &_ec, future<> _precondition, metadata_flags _metadata, size_t _maxitems = 2,
05575   bool _restart = true, path _glob = path(), enumerate_req::filter _filtering = enumerate_req::filter::fastdeleted)
05576 {
05577   auto ret = detail::async_enumerate(_maxitems, _restart, std::move(_glob), _metadata, _filtering)(std::move(_precondition));
05578   if (!(_ec = ret.get_error()))
05579     return ret.get();
05580   return std::pair<std::vector<directory_entry>, bool>();
05581 }
05582 
05583 
05601 inline future<std::vector<std::pair<off_t, off_t>>> async_extents(future<> _precondition)
05602 {
05603   return detail::async_extents()(std::move(_precondition));
05604 }
05623 inline std::vector<std::pair<off_t, off_t>> extents(future<> _precondition)
05624 {
05625   return detail::async_extents()(std::move(_precondition)).get();
05626 }
05646 inline std::vector<std::pair<off_t, off_t>> extents(error_code &_ec, future<> _precondition)
05647 {
05648   auto ret = detail::async_extents()(std::move(_precondition));
05649   if (!(_ec = ret.get_error()))
05650     return ret.get();
05651   return std::vector<std::pair<off_t, off_t>>();
05652 }
05653 
05654 
05674 inline future<statfs_t> async_statfs(future<> _precondition, fs_metadata_flags req)
05675 {
05676   return detail::async_statfs(req)(std::move(_precondition));
05677 }
05698 inline statfs_t statfs(future<> _precondition, fs_metadata_flags req)
05699 {
05700   return detail::async_statfs(req)(std::move(_precondition)).get();
05701 }
05723 inline statfs_t statfs(error_code &_ec, future<> _precondition, fs_metadata_flags req)
05724 {
05725   auto ret = detail::async_statfs(req)(std::move(_precondition));
05726   if (!(_ec = ret.get_error()))
05727     return ret.get();
05728   return statfs_t();
05729 }
05730 
05738 inline future<> depends(future<> precondition, future<> out)
05739 {
05740   return precondition.parent()->depends(precondition, out);
05741 }
05742 
05744 namespace utils
05745 {
05754   BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC std::vector<size_t> page_sizes(bool only_actually_available = true) noexcept;
05755 
05764   inline size_t file_buffer_default_size() noexcept
05765   {
05766     static size_t size;
05767     if (!size)
05768     {
05769       std::vector<size_t> sizes(page_sizes(true));
05770       for (auto &i : sizes)
05771         if (i >= 1024 * 1024)
05772         {
05773           size = i;
05774           break;
05775         }
05776       if (!size)
05777         size = 1024 * 1024;
05778     }
05779     return size;
05780   }
05781 
05790   BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC void random_fill(char *buffer, size_t bytes);
05791 
05804 #ifdef _MSC_VER
05805 #pragma warning(push)
05806 #pragma warning(disable: 6293) // MSVC sanitiser warns that we wrap n in the for loop
05807 #endif
05808   inline size_t to_hex_string(char *out, size_t outlen, const char *_in, size_t inlen)
05809   {
05810     unsigned const char *in = (unsigned const char *) _in;
05811     static BOOST_CONSTEXPR_OR_CONST char table[] = "0123456789abcdef";
05812     if(outlen<inlen*2)
05813       BOOST_AFIO_THROW(std::invalid_argument("Output buffer too small."));
05814     for (size_t n = inlen - 2; n <= inlen - 2; n-=2)
05815     {
05816       out[n * 2 + 3] = table[(in[n+1] >> 4) & 0xf];
05817       out[n * 2 + 2] = table[in[n+1] & 0xf];
05818       out[n * 2 + 1] = table[(in[n] >> 4) & 0xf];
05819       out[n * 2 + 0] = table[in[n] & 0xf];
05820     }
05821     if(inlen&1)
05822     {
05823       out[1] = table[(in[0] >> 4) & 0xf];
05824       out[0] = table[in[0] & 0xf];
05825     }
05826     return inlen*2;
05827   }
05828 #ifdef _MSC_VER
05829 #pragma warning(pop)
05830 #endif
05831 
05832   inline std::string to_hex_string(std::string in)
05833   {
05834     std::string out(in.size() * 2, ' ');
05835     to_hex_string(const_cast<char *>(out.data()), out.size(), in.data(), in.size());
05836     return out;
05837   }
05838 
05847   inline size_t from_hex_string(char *out, size_t outlen, const char *in, size_t inlen)
05848   {
05849     if (inlen % 2)
05850       BOOST_AFIO_THROW(std::invalid_argument("Input buffer not multiple of two."));
05851     if (outlen<inlen / 2)
05852       BOOST_AFIO_THROW(std::invalid_argument("Output buffer too small."));
05853     bool is_invalid=false;
05854     auto fromhex = [&is_invalid](char c) -> unsigned char
05855     {
05856 #if 1
05857       // ASCII starting from 48 is 0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
05858       //                           48               65                              97
05859       static BOOST_CONSTEXPR_OR_CONST unsigned char table[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,                                                    // +10 = 58
05860         255, 255, 255, 255, 255, 255, 255,                                                                                                      // +7  = 65
05861         10, 11, 12, 13, 14, 15,                                                                                                                 // +6  = 71
05862         255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,       // +26 = 97
05863         10, 11, 12, 13, 14, 15
05864       };
05865       unsigned char r=255;
05866       if(c>=48 && c<=102)
05867         r=table[c-48];
05868       if(r==255)
05869         is_invalid=true;
05870       return r;
05871 #else
05872       if(c>='0' && c<='9')
05873         return c-'0';
05874       if(c>='a' && c<='f')
05875         return c-'a'+10;
05876       if(c>='A' && c<='F')
05877         return c-'A'+10;
05878       BOOST_AFIO_THROW(std::invalid_argument("Input is not hexadecimal."));
05879 #endif
05880     };
05881     for (size_t n = 0; n<inlen/2; n+=4)
05882     {
05883       unsigned char c[8];
05884       c[0]= fromhex(in[n * 2]);
05885       c[1]= fromhex(in[n * 2 + 1]);
05886       c[2]= fromhex(in[n * 2 + 2]);
05887       c[3]= fromhex(in[n * 2 + 3]);
05888       out[n]=(c[1]<<4)|c[0];
05889       c[4]= fromhex(in[n * 2 + 4]);
05890       c[5]= fromhex(in[n * 2 + 5]);
05891       out[n+1]=(c[3]<<4)|c[2];
05892       c[6]= fromhex(in[n * 2 + 6]);
05893       c[7]= fromhex(in[n * 2 + 7]);
05894       out[n+2]=(c[5]<<4)|c[4];
05895       out[n+3]=(c[7]<<4)|c[6];
05896     }
05897     for (size_t n = inlen/2-(inlen/2)%4; n<inlen/2; n++)
05898     {
05899       unsigned char c1 = fromhex(in[n * 2]), c2 = fromhex(in[n * 2 + 1]);
05900       out[n]=(c2<<4)|c1;
05901     }
05902     if(is_invalid)
05903       BOOST_AFIO_THROW(std::invalid_argument("Input is not hexadecimal."));
05904     return inlen/2;
05905   }
05906 
05915   inline std::string random_string(size_t randomlen)
05916   {
05917     size_t outlen = randomlen*2;
05918     std::string ret(outlen, 0);
05919     random_fill(const_cast<char *>(ret.data()), randomlen);
05920     to_hex_string(const_cast<char *>(ret.data()), outlen, ret.data(), randomlen);
05921     return ret;
05922   }
05923 
05924 #ifndef BOOST_AFIO_SECDEC_INTRINSICS
05925 # if defined(__GCC__) || defined(__clang__)
05926 #  define BOOST_AFIO_SECDEC_INTRINSICS 1
05927 # elif defined(_MSC_VER) && (defined(_M_X64) || _M_IX86_FP==1)
05928 #  define BOOST_AFIO_SECDEC_INTRINSICS 1
05929 # endif
05930 #endif
05931 #ifndef BOOST_AFIO_SECDEC_INTRINSICS
05932 # define BOOST_AFIO_SECDEC_INTRINSICS 0
05933 #endif
05934 
05968   template<size_t blocksize> class secded_ecc
05969   {
05970   public:
05971     typedef unsigned int result_type; 
05972   private:
05973     static BOOST_CONSTEXPR_OR_CONST size_t bits_per_byte=8;
05974     typedef unsigned char unit_type;  // The batch unit of processing
05975     result_type bitsvalid;
05976     // Many CPUs (x86) are slow doing variable bit shifts, so keep a table
05977     result_type ecc_twospowers[sizeof(result_type)*bits_per_byte];
05978     unsigned short ecc_table[blocksize*bits_per_byte];
05979     static bool _is_single_bit_set(result_type x)
05980     {
05981 #ifndef _MSC_VER
05982 #if defined(__i386__) || defined(__x86_64__)
05983 #ifndef __SSE4_2__
05984       // Do a once off runtime check
05985       static int have_popcnt=[]{
05986         size_t cx, dx;
05987 #if defined(__x86_64__)
05988         asm("cpuid": "=c" (cx), "=d" (dx) : "a" (1), "b" (0), "c" (0), "d" (0));
05989 #else
05990         asm("pushl %%ebx\n\tcpuid\n\tpopl %%ebx\n\t": "=c" (cx), "=d" (dx) : "a" (1), "c" (0), "d" (0));
05991 #endif
05992         return (dx&(1<<26))!=0/*SSE2*/ && (cx&(1<<23))!=0/*POPCNT*/;
05993       }();
05994       if(have_popcnt)
05995 #endif
05996       {
05997         unsigned count;
05998         asm("popcnt %1,%0" : "=r"(count) : "rm"(x) : "cc");
05999         return count==1;
06000       }
06001 #endif
06002       return __builtin_popcount(x)==1;
06003 #else
06004       x -= (x >> 1) & 0x55555555;
06005       x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
06006       x = (x + (x >> 4)) & 0x0f0f0f0f;
06007       unsigned int count=(x * 0x01010101)>>24;
06008       return count==1;
06009 #if 0
06010       x -= (x >> 1) & 0x5555555555555555ULL;
06011       x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
06012       x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
06013       unsigned long long count=(x * 0x0101010101010101ULL)>>56;
06014       return count==1;
06015 #endif
06016 #endif
06017     }
06018   public:
06020     BOOST_CXX14_CONSTEXPR secded_ecc()
06021     {
06022       for(size_t n=0; n<sizeof(result_type)*bits_per_byte; n++)
06023         ecc_twospowers[n]=((result_type)1<<n);
06024       result_type length=blocksize*bits_per_byte;
06025       // This is (data bits + parity bits + 1) <= 2^(parity bits)
06026       for(result_type p=1; p<sizeof(result_type)*bits_per_byte; p++)
06027         if((length+p+1)<=ecc_twospowers[p])
06028         {
06029           bitsvalid=p;
06030           break;
06031         }
06032       if((bits_per_byte-1+bitsvalid)/bits_per_byte>sizeof(result_type))
06033         BOOST_AFIO_THROW(std::runtime_error("ECC would exceed the size of result_type!"));
06034       for(result_type i=0; i<blocksize*bits_per_byte; i++)
06035       {
06036         // Make a code bit
06037         result_type b=i+1;
06038 #if BOOST_AFIO_SECDEC_INTRINSICS && 0 // let constexpr do its thing
06039 #ifdef _MSC_VER
06040         unsigned long _topbit;
06041         _BitScanReverse(&_topbit, b);
06042         result_type topbit=_topbit;
06043 #else
06044         result_type topbit=bits_per_byte*sizeof(result_type)-__builtin_clz(b);
06045 #endif
06046         b+=topbit;
06047         if(b>=ecc_twospowers[topbit]) b++;
06048         //while(b>ecc_twospowers(_topbit+1)) _topbit++;
06049         //b+=_topbit;
06050         //if(b>=ecc_twospowers(_topbit)) b++;
06051 #else
06052         for(size_t p=0; ecc_twospowers[p]<(b+1); p++)
06053           b++;
06054 #endif
06055         ecc_table[i]=(unsigned short) b;
06056         if(b>(unsigned short)-1)
06057           BOOST_AFIO_THROW(std::runtime_error("Precalculated table has exceeded its bounds"));
06058       }
06059     }
06061     constexpr result_type result_bits_valid() const noexcept
06062     {
06063       return bitsvalid;
06064     }
06066     result_type operator()(result_type ecc, const char *buffer) const noexcept
06067     {
06068       if(blocksize<sizeof(unit_type)*8)
06069         return (*this)(ecc, buffer, blocksize);
06070       // Process in lumps of eight
06071       const unit_type *_buffer=(const unit_type *) buffer;
06072 //#pragma omp parallel for reduction(^:ecc)
06073       for(size_t i=0; i<blocksize; i+=sizeof(unit_type)*8)
06074       {
06075         union { unsigned long long v; unit_type c[8]; };
06076         result_type prefetch[8];
06077         v=*(unsigned long long *)(&_buffer[0+i/sizeof(unit_type)]); // min 1 cycle
06078 #define BOOST_AFIO_ROUND(n) \
06079           prefetch[0]=ecc_table[(i+0)*8+n]; \
06080           prefetch[1]=ecc_table[(i+1)*8+n]; \
06081           prefetch[2]=ecc_table[(i+2)*8+n]; \
06082           prefetch[3]=ecc_table[(i+3)*8+n]; \
06083           prefetch[4]=ecc_table[(i+4)*8+n]; \
06084           prefetch[5]=ecc_table[(i+5)*8+n]; \
06085           prefetch[6]=ecc_table[(i+6)*8+n]; \
06086           prefetch[7]=ecc_table[(i+7)*8+n]; \
06087           if(c[0]&((unit_type)1<<n))\
06088             ecc^=prefetch[0];\
06089           if(c[1]&((unit_type)1<<n))\
06090             ecc^=prefetch[1];\
06091           if(c[2]&((unit_type)1<<n))\
06092             ecc^=prefetch[2];\
06093           if(c[3]&((unit_type)1<<n))\
06094             ecc^=prefetch[3];\
06095           if(c[4]&((unit_type)1<<n))\
06096             ecc^=prefetch[4];\
06097           if(c[5]&((unit_type)1<<n))\
06098             ecc^=prefetch[5];\
06099           if(c[6]&((unit_type)1<<n))\
06100             ecc^=prefetch[6];\
06101           if(c[7]&((unit_type)1<<n))\
06102             ecc^=prefetch[7];
06103         BOOST_AFIO_ROUND(0)                                                    // prefetch = min 8, bit test and xor = min 16, total = 24
06104         BOOST_AFIO_ROUND(1)
06105         BOOST_AFIO_ROUND(2)
06106         BOOST_AFIO_ROUND(3)
06107         BOOST_AFIO_ROUND(4)
06108         BOOST_AFIO_ROUND(5)
06109         BOOST_AFIO_ROUND(6)
06110         BOOST_AFIO_ROUND(7)
06111   #undef BOOST_AFIO_ROUND                                                      // total should be 1+(8*24/3)=65
06112       }
06113       return ecc;
06114     }
06115     result_type operator()(const char *buffer) const noexcept { return (*this)(0, buffer); }
06117     result_type operator()(result_type ecc, const char *buffer, size_t length) const noexcept
06118     {
06119       const unit_type *_buffer=(const unit_type *) buffer;
06120 //#pragma omp parallel for reduction(^:ecc)
06121       for(size_t i=0; i<length; i+=sizeof(unit_type))
06122       {
06123         unit_type c=_buffer[i/sizeof(unit_type)];                 // min 1 cycle
06124         if(!c)                                                    // min 1 cycle
06125           continue;
06126         char bitset[bits_per_byte*sizeof(unit_type)];
06127         result_type prefetch[bits_per_byte*sizeof(unit_type)];
06128         // Most compilers will roll this out
06129         for(size_t n=0; n<bits_per_byte*sizeof(unit_type); n++)   // min 16 cycles
06130         {
06131           bitset[n]=!!(c&((unit_type)1<<n));
06132           prefetch[n]=ecc_table[i*bits_per_byte+n];               // min 8 cycles
06133         }
06134         result_type localecc=0;
06135         for(size_t n=0; n<bits_per_byte*sizeof(unit_type); n++)
06136         {
06137           if(bitset[n])                                           // min 8 cycles
06138             localecc^=prefetch[n];                                // min 8 cycles
06139         }
06140         ecc^=localecc;                                            // min 1 cycle. Total cycles = min 43 cycles/byte
06141       }
06142       return ecc;
06143     }
06144     result_type operator()(const char *buffer, size_t length) const noexcept { return (*this)(0, buffer, length); }
06146     result_type find_bad_bit(result_type good_ecc, result_type bad_ecc) const noexcept
06147     {
06148       result_type length=blocksize*bits_per_byte, eccdiff=good_ecc^bad_ecc;
06149       if(_is_single_bit_set(eccdiff))
06150         return (result_type)-1;
06151       for(result_type i=0, b=1; i<length; i++, b++)
06152       {
06153         // Skip parity bits
06154         while(_is_single_bit_set(b))
06155           b++;
06156         if(b==eccdiff)
06157           return i;
06158       }
06159       return (result_type)-1;
06160     }
06162     enum verify_status
06163     {
06164       corrupt=0,  
06165       okay=1,     
06166       healed=2    
06167     };
06169     verify_status verify(char *buffer, result_type good_ecc) const noexcept
06170     {
06171       result_type this_ecc=(*this)(0, buffer);
06172       if(this_ecc==good_ecc)
06173         return verify_status::okay; // no errors
06174       result_type badbit=find_bad_bit(good_ecc, this_ecc);
06175       if((result_type)-1==badbit)
06176         return verify_status::corrupt; // parity corrupt?
06177       buffer[badbit/bits_per_byte]^=(unsigned char) ecc_twospowers[badbit%bits_per_byte];
06178       this_ecc=(*this)(0, buffer);
06179       if(this_ecc==good_ecc)
06180         return healed; // error healed
06181       // Put the bit back
06182       buffer[badbit/bits_per_byte]^=(unsigned char) ecc_twospowers[badbit%bits_per_byte];
06183       return verify_status::corrupt; // more than one bit was corrupt
06184     }
06185   };
06186  
06187   namespace detail
06188   {
06189     struct large_page_allocation
06190     {
06191       void *p;
06192       size_t page_size_used;
06193       size_t actual_size;
06194       large_page_allocation() : p(nullptr), page_size_used(0), actual_size(0) { }
06195       large_page_allocation(void *_p, size_t pagesize, size_t actual) : p(_p), page_size_used(pagesize), actual_size(actual) { }
06196     };
06197     inline large_page_allocation calculate_large_page_allocation(size_t bytes)
06198     {
06199       large_page_allocation ret;
06200       auto pagesizes(page_sizes());
06201       do
06202       {
06203         ret.page_size_used=pagesizes.back();
06204         pagesizes.pop_back();
06205       } while(!pagesizes.empty() && !(bytes/ret.page_size_used));
06206       ret.actual_size=(bytes+ret.page_size_used-1)&~(ret.page_size_used-1);
06207       return ret;    
06208     }
06209     BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC large_page_allocation allocate_large_pages(size_t bytes);
06210     BOOST_AFIO_HEADERS_ONLY_FUNC_SPEC void deallocate_large_pages(void *p, size_t bytes);
06211   }
06230   template <typename T>
06231   class page_allocator
06232   {
06233   public:
06234       typedef T         value_type;
06235       typedef T*        pointer;
06236       typedef const T*  const_pointer;
06237       typedef T& reference;
06238       typedef const T&  const_reference;
06239       typedef size_t    size_type;
06240       typedef ptrdiff_t difference_type;
06241       typedef std::true_type propagate_on_container_move_assignment;
06242       typedef std::true_type is_always_equal;
06243 
06244       template <class U>
06245       struct rebind { typedef page_allocator<U> other; };
06246 
06247       page_allocator() noexcept
06248       {}
06249 
06250       template <class U>
06251       page_allocator(const page_allocator<U>&) noexcept
06252       {}
06253 
06254       size_type
06255       max_size() const noexcept
06256       { return size_type(~0) / sizeof(T); }
06257 
06258       pointer
06259       address(reference x) const noexcept
06260       { return std::addressof(x); }
06261 
06262       const_pointer
06263       address(const_reference x) const noexcept
06264       { return std::addressof(x); }
06265 
06266       pointer
06267       allocate(size_type n, const void *hint = 0)
06268       {
06269           if(n>max_size())
06270               throw std::bad_alloc();
06271           auto mem(detail::allocate_large_pages(n * sizeof(T)));
06272           if (mem.p == nullptr)
06273               throw std::bad_alloc();
06274           return reinterpret_cast<pointer>(mem.p);
06275       }
06276 
06277       void
06278       deallocate(pointer p, size_type n)
06279       {
06280           if(n>max_size())
06281               throw std::bad_alloc();
06282           detail::deallocate_large_pages(p, n * sizeof(T));
06283       }
06284 
06285       template <class U, class ...Args>
06286       void
06287       construct(U* p, Args&&... args)
06288       { ::new(reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...); }
06289 
06290       template <class U> void
06291       destroy(U* p)
06292       { p->~U(); }
06293   };
06294   template <>
06295   class page_allocator<void>
06296   {
06297   public:
06298       typedef void         value_type;
06299       typedef void*        pointer;
06300       typedef const void*  const_pointer;
06301       typedef std::true_type propagate_on_container_move_assignment;
06302       typedef std::true_type is_always_equal;
06303 
06304       template <class U>
06305       struct rebind { typedef page_allocator<U> other; };
06306   };
06307   template<class T, class U> inline bool operator==(const page_allocator<T> &, const page_allocator<U> &) noexcept { return true; }
06308 }
06309 
06310 
06311 BOOST_AFIO_V2_NAMESPACE_END
06312 
06313 // Specialise std::hash<> for directory_entry
06314 #ifndef BOOST_AFIO_DISABLE_STD_HASH_SPECIALIZATION
06315 #include <functional>
06316 namespace std
06317 {
06318     template<> struct hash<BOOST_AFIO_V2_NAMESPACE::path>
06319     {
06320     public:
06321         size_t operator()(const BOOST_AFIO_V2_NAMESPACE::path &p) const
06322         {
06323             return BOOST_AFIO_V2_NAMESPACE::path_hash()(p);
06324         }
06325     };
06326     template<> struct hash<BOOST_AFIO_V2_NAMESPACE::directory_entry>
06327     {
06328     public:
06329         size_t operator()(const BOOST_AFIO_V2_NAMESPACE::directory_entry &p) const
06330         {
06331             return BOOST_AFIO_V2_NAMESPACE::directory_entry_hash()(p);
06332         }
06333     };
06334 
06335 }//namesapce std
06336 #endif
06337 
06338 #ifdef BOOST_MSVC
06339 #pragma warning(pop)
06340 #endif
06341 
06342 #if BOOST_AFIO_HEADERS_ONLY == 1 && !defined(DOXYGEN_SHOULD_SKIP_THIS)
06343 #undef BOOST_AFIO_VALIDATE_INPUTS // Let BOOST_AFIO_NEVER_VALIDATE_INPUTS take over
06344 #define BOOST_AFIO_HEADER_INCLUDED 1
06345 #include "detail/impl/afio.ipp"
06346 #undef BOOST_AFIO_HEADER_INCLUDED
06347 #endif
06348 
06349 #endif
06350 #endif

January, 2014

Copyright © 2013-2014 Niall Douglas, Cork, Ireland
Copyright © 2013 Paul Kirth, California
Documentation is generated by Doxygen