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 |