Skip to content

Commit

Permalink
Rename boost.monad to boost.outcome
Browse files Browse the repository at this point in the history
  • Loading branch information
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com) committed Sep 8, 2015
1 parent 30c2ca2 commit d29a2d7
Show file tree
Hide file tree
Showing 17 changed files with 93 additions and 94 deletions.
7 changes: 3 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@
path = include/boost/afio/bindlib
url = https://github.com/ned14/Boost.BindLib.git
branch = master
[submodule "include/boost/afio/monad"]
path = include/boost/afio/monad
url = https://github.com/ned14/boost.monad.git
branch = master
[submodule "include/boost/afio/v1/branch"]
path = include/boost/afio/v1/branch
url = https://github.com/BoostGSoC13/boost.afio.git
branch = v1.3_Boost_v1.58_branch
[submodule "include/boost/afio/outcome"]
path = include/boost/afio/outcome
url = https://github.com/ned14/boost.outcome.git
2 changes: 1 addition & 1 deletion build/afio.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeOutput>afio.exe</NMakeOutput>
<NMakePreprocessorDefinitions>WIN32;_DEBUG;$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>
<NMakeBuildCommandLine>..\..\..\b2 address-model=64 link=static ../test --link-test -j 8 pch=off --test=../example/workshop_final_afio.cpp</NMakeBuildCommandLine>
<NMakeBuildCommandLine>..\..\..\b2 address-model=64 link=static ../test --link-test -j 8</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>..\..\..\b2 address-model=64 -a</NMakeReBuildCommandLine>
<IncludePath>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);..\..\..</IncludePath>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion doc/afio.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
[def __boost__ Boost]
[def __boost_afio__ Boost.AFIO]
[def __boost_bindlib__ [@https://github.com/ned14/Boost.APIBind Boost.APIBind]]
[def __boost_monad__ [@https://ned14.github.io/boost.monad/group__future__promise.html Boost.Monad]]
[def __boost_outcome__ [@https://ned14.github.io/boost.outcome/group__future__promise.html Boost.Outcome]]
[def __triplegit__ TripleGit]
[def __fileurl__ file:///]
[def __dash__ \u2014]
Expand Down
6 changes: 3 additions & 3 deletions doc/design_rationale.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ an opaque abstract base class. When constructed using __afio_make_dispatcher__ y
namespace the dispatcher will dispatch onto. You can create your own custom `dispatcher` implementations for some URI regex pattern too.

* AFIO provides its own custom future type `afio::__afio_op__<T = void>` which [*always] represents a future `handle_ptr` plus an optional `T`
which is usually `void` (hence defaulting `T` to `void`). This custom future type is implemented using __boost_monad__'s lightweight
which is usually `void` (hence defaulting `T` to `void`). This custom future type is implemented using __boost_outcome__'s lightweight
monadic future factory toolkit, and therefore provides all the C++ 1z Concurrency TS and __boost_thread__ extensions including
continuations and wait composure. Note that lightweight futures can carry an `error_code` as well as an `exception_ptr`, and therefore
much of the need for non-throwing `error_code` taking API overloads is not needed (though any function not returning a future still
Expand Down Expand Up @@ -46,7 +46,7 @@ API which consumes a future can throw (unless you know for a fact the future is
not errored).

[note Gathering error states from many futures at once is made easier using the `when_all_p()`
(when all propagating) extended wait composure function from __boost_monad__ __dash__ this
(when all propagating) extended wait composure function from __boost_outcome__ __dash__ this
propagates any error in any of the entry futures into the composed output future, thus saving
you having to check the futures for errors by hand.]

Expand Down Expand Up @@ -180,7 +180,7 @@ to keep the continuations information per future. This had the big advantage tha
futures could be used, but it came with many other problems, mainly performance and code complexity related.
An additional problem was that the Concurrency TS had moved on considerably since 2012, and AFIO's emulation
was now significantly out of date.
For v1.4 a new lightweight future-promise factory toolkit library called __boost_monad__ was written between the
For v1.4 a new lightweight future-promise factory toolkit library called __boost_outcome__ was written between the
end of C++ Now (May) and the beginning of the AFIO peer review (July) which makes
easy the writing of arbitrarily customisable future-promises for C++ which:

Expand Down
2 changes: 1 addition & 1 deletion doc/generated/group_async_file_io_dispatcher.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ URIs currently supported by AFIO:


[heading Synopsis]
``BOOST_AFIO_DECL monad<dispatcher_ptr> make_dispatcher(std::string uri = "file : / / /", file_flags flagsforce = file_flags::none, file_flags flagsmask = file_flags::none,
``BOOST_AFIO_DECL 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())``

[heading Parameters]
Expand Down
20 changes: 10 additions & 10 deletions doc/quickstart.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ to v2 you mean v2 and nothing but v2. If you just wanted the current AFIO, simpl
`boost::afio` as with other libraries, this picks up whatever the current configuration and version of
AFIO is.

The `monad<>` comes from __boost_monad__ which is a dependency of __boost_afio__. It has an identical
The `outcome<>` comes from __boost_outcome__ which is a dependency of __boost_afio__. It has an identical
API to `std::future<>` or more rather `boost::future<>`, so simply treat it as an always ready future.
`monad<>` here can return a shared pointer to the iostream, or empty (item not found), or an error, or
`outcome<>` here can return a shared pointer to the iostream, or empty (item not found), or an error, or
an exception as you can see in this example use case:

[workshop_use_naive]
Expand All @@ -77,7 +77,7 @@ A perfectly straightforward and simple way of implementing `data_store` using pu

[workshop_naive]

Note that `monad<T>` implicitly consumes any `T`, `std::error_code`, `std::exception_ptr` or `empty`, hence
Note that `outcome<T>` implicitly consumes any `T`, `std::error_code`, `std::exception_ptr` or `empty`, hence
the ability to return any of those directly.

This very simple solution assumes that the key-value store is a directory in the current path called ["store] and
Expand Down Expand Up @@ -156,7 +156,7 @@ quickly __dash__ indeed far faster than copying 4Kb of memory and often quicker
complete before scheduling the next write in order to report any errors which occurred during the write.

This is the first use of asynchronous i/o in this tutorial. AFIO provides a custom `future<T>` type extending
the lightweight monadic futures framework in __boost_monad__, so you get all the
the lightweight monadic futures framework in __boost_outcome__, so you get all the
[@http://www.drdobbs.com/parallel/improving-futures-and-callbacks-in-c-to/240004255 C++ 1z Concurrency TS extensions],
[@http://blogs.msdn.com/b/vcblog/archive/2014/11/12/resumable-functions-in-c.aspx C++ 1z coroutines support] and
[@http://www.boost.org/doc/html/thread/synchronization.html#thread.synchronization.futures Boost.Thread future extensions] in the AFIO custom `future<>`. There are also many
Expand All @@ -179,7 +179,7 @@ additional extensions beyond what Boost.Thread or the Concurrency TS provides, i
[section:naive_afio_async 3. World's simplest named blob store in AFIO (asynchronous)]

Let's see the same exact thing as in the last section, but this time with a fully asynchronous public interface.
Instead of returning `monad<>`, we now return `shared_future<>`:
Instead of returning `outcome<>`, we now return `shared_future<>`:

[workshop_naive_async_afio_interface]

Expand All @@ -188,7 +188,7 @@ convert from their allowed monadic input types without you needing to write `mak
Concurrency TS.

You may be interested to know that the benchmarking harness code is 100% identical for all three of these
implementations. This is because `monad<>` is sufficiently API-identical to `future<>` that identical code can drive all
implementations. This is because `outcome<>` is sufficiently API-identical to `future<>` that identical code can drive all
three implementations.

`write()` is now implemented by scheduling the file to be opened for write access and attaching a continuation
Expand All @@ -203,7 +203,7 @@ a second continuation to return the input stream.

The below pattern is 100% pure soon-to-be-standardised Concurrency TS future continuations which can be easily coroutinised
automatically on a C++ 1z Coroutines supporting compiler (simply insert `await` before any AFIO `async_XXX` function). Apart from the fact that
__boost_monad__ lightweight futures also provide an `error_code` transport, there is nothing below which wouldn't
__boost_outcome__ lightweight futures also provide an `error_code` transport, there is nothing below which wouldn't
work with an upcoming standard C++ library (unless the TS changes substantially, which is very unlikely at this late
stage).

Expand Down Expand Up @@ -262,7 +262,7 @@ implementation is far faster and will [*always] be faster than AFIO if you do a
is pretty much this benchmark in a nutshell.

[note This peer review edition of AFIO v1.40 uses a mocked up v1.40 API based on the v1.3 series engine. Performance
of this mockup will be considerably below the final v1.40 engine written using __boost_monad__'s lightweight futures.]
of this mockup will be considerably below the final v1.40 engine written using __boost_outcome__'s lightweight futures.]

A design which makes better use of AFIO is one which is asynchronous throughout and which avoids file opens and closes
(['tip:] always avoid file opens period if you want fast filesystem performance, they are always very slow due
Expand Down Expand Up @@ -795,10 +795,10 @@ deallocate the rest.

So let's look at our new interface file. It looks pretty similar to before, the only real change is the many new
private member variable `handle_ptr`'s to the store files described above. Another change is that we now return
a `monad<ostream>` for writing but a `shared_future<istream>` for reading __dash__ this is because as explained
a `outcome<ostream>` for writing but a `shared_future<istream>` for reading __dash__ this is because as explained
earlier, writes are now fully buffered to memory before being hashed and committed as a transaction, so by explicitly
returning a monad we are saying that this is now a synchronous operation (one could just return an already ready
shared future, but this method makes public API assurances, and because a __boost_monad__ future is a monad,
shared future, but this method makes public API assurances, and because a __boost_outcome__ future is a monad,
your code will likely not even notice).

[workshop_final_interface]
Expand Down
2 changes: 1 addition & 1 deletion doc/release_notes.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ version to enter Boost if accepted]

This peer review edition of AFIO v1.4 has been ["mocked up] with an API which should very closely
resemble the eventual API in the v1.4 engine which will be rewritten to use the just written
lightweight future-promise factory toolkit in forthcoming __boost_monad__. It is, however,
lightweight future-promise factory toolkit in forthcoming __boost_outcome__. It is, however,
still in fact the mature v1.3 engine with a faked wrapper API simulating the v1.4 engine.
Known deviations from the eventual v1.4 release:

Expand Down
12 changes: 6 additions & 6 deletions example/workshop_atomic_updates_afio.ipp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//[workshop_atomic_updates_afio_interface
namespace afio = BOOST_AFIO_V2_NAMESPACE;
namespace filesystem = BOOST_AFIO_V2_NAMESPACE::filesystem;
using BOOST_MONAD_V1_NAMESPACE::lightweight_futures::shared_future;
using BOOST_OUTCOME_V1_NAMESPACE::lightweight_futures::shared_future;

class data_store
{
Expand Down Expand Up @@ -32,7 +32,7 @@ public:

//[workshop_atomic_updates_afio3]
namespace asio = BOOST_AFIO_V2_NAMESPACE::asio;
using BOOST_MONAD_V1_NAMESPACE::empty;
using BOOST_OUTCOME_V1_NAMESPACE::empty;
using BOOST_AFIO_V2_NAMESPACE::error_code;
using BOOST_AFIO_V2_NAMESPACE::generic_category;

Expand Down Expand Up @@ -160,7 +160,7 @@ struct odirectstream : public std::ostream

//[workshop_atomic_updates_afio1]
namespace asio = BOOST_AFIO_V2_NAMESPACE::asio;
using BOOST_MONAD_V1_NAMESPACE::empty;
using BOOST_OUTCOME_V1_NAMESPACE::empty;
using BOOST_AFIO_V2_NAMESPACE::error_code;
using BOOST_AFIO_V2_NAMESPACE::generic_category;

Expand Down Expand Up @@ -218,7 +218,7 @@ shared_future<data_store::istream> data_store::lookup(std::string name) noexcept
// When it completes, call this continuation
return h.then([](afio::future<> &_h) -> shared_future<data_store::istream> {
// If file didn't open, return the error or exception immediately
BOOST_MONAD_PROPAGATE(_h);
BOOST_OUTCOME_PROPAGATE(_h);
size_t length=(size_t) _h->lstat(afio::metadata_flags::size).st_size;
// Is a memory map more appropriate?
if(length>=128*1024)
Expand All @@ -236,7 +236,7 @@ shared_future<data_store::istream> data_store::lookup(std::string name) noexcept
// When the read completes call this continuation
return h.then([buffer, length](const afio::future<> &h) -> shared_future<data_store::istream> {
// If read failed, return the error or exception immediately
BOOST_MONAD_PROPAGATE(h);
BOOST_OUTCOME_PROPAGATE(h);
data_store::istream ret(std::make_shared<idirectstream>(h.get_handle(), buffer, length));
return ret;
});
Expand Down Expand Up @@ -276,7 +276,7 @@ shared_future<data_store::ostream> data_store::write(std::string name) noexcept
// When it completes, call this continuation
return h.then([](const afio::future<> &h) -> shared_future<data_store::ostream> {
// If file didn't open, return the error or exception immediately
BOOST_MONAD_PROPAGATE(h);
BOOST_OUTCOME_PROPAGATE(h);
// Create an ostream which directly uses the file.
data_store::ostream ret(std::make_shared<odirectstream>(h.get_handle()));
return std::move(ret);
Expand Down
28 changes: 14 additions & 14 deletions example/workshop_final_afio.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
//[workshop_final_interface
namespace afio = BOOST_AFIO_V2_NAMESPACE;
namespace filesystem = BOOST_AFIO_V2_NAMESPACE::filesystem;
using BOOST_MONAD_V1_NAMESPACE::monad;
using BOOST_MONAD_V1_NAMESPACE::lightweight_futures::shared_future;
using BOOST_OUTCOME_V1_NAMESPACE::outcome;
using BOOST_OUTCOME_V1_NAMESPACE::lightweight_futures::shared_future;

class data_store
{
Expand All @@ -27,7 +27,7 @@ public:
// Type used for lookup
using lookup_result_type = shared_future<istream>;
// Type used for write
using write_result_type = monad<ostream>;
using write_result_type = outcome<ostream>;

// Disposition flags
static constexpr size_t writeable = (1<<0);
Expand All @@ -38,15 +38,15 @@ public:
// Look up item named name for reading, returning an istream for the item
shared_future<istream> lookup(std::string name) noexcept;
// Look up item named name for writing, returning an ostream for that item
monad<ostream> write(std::string name) noexcept;
outcome<ostream> write(std::string name) noexcept;
};
//]

//[workshop_final1]
namespace asio = BOOST_AFIO_V2_NAMESPACE::asio;
using BOOST_AFIO_V2_NAMESPACE::error_code;
using BOOST_AFIO_V2_NAMESPACE::generic_category;
using BOOST_MONAD_V1_NAMESPACE::monad;
using BOOST_OUTCOME_V1_NAMESPACE::outcome;

// A special allocator of highly efficient file i/o memory
using file_buffer_type = std::vector<char, afio::utils::file_buffer_allocator<char>>;
Expand Down Expand Up @@ -118,7 +118,7 @@ struct data_store::index
last_good_ondisk_index_info() : offset(0), size(0) { }
};
// Finds the last good index in the store
monad<last_good_ondisk_index_info> find_last_good_ondisk_index(afio::handle_ptr h) noexcept
outcome<last_good_ondisk_index_info> find_last_good_ondisk_index(afio::handle_ptr h) noexcept
{
last_good_ondisk_index_info ret;
error_code ec;
Expand Down Expand Up @@ -262,11 +262,11 @@ start_linear_scan:
//]
//[workshop_final3]
// Loads the index from the store
monad<void> load(afio::handle_ptr h) noexcept
outcome<void> load(afio::handle_ptr h) noexcept
{
// If find_last_good_ondisk_index() returns error or exception, return those, else
// initialise ondisk_index_info to monad.get()
BOOST_MONAD_AUTO(ondisk_index_info, find_last_good_ondisk_index(h));
BOOST_OUTCOME_AUTO(ondisk_index_info, find_last_good_ondisk_index(h));
error_code ec;
try
{
Expand All @@ -291,7 +291,7 @@ start_linear_scan:
//]
//[workshop_final4]
// Writes the index to the store
monad<void> store(afio::handle_ptr rwh, afio::handle_ptr appendh) noexcept
outcome<void> store(afio::handle_ptr rwh, afio::handle_ptr appendh) noexcept
{
error_code ec;
std::vector<ondisk_index_regions::ondisk_index_region> ondisk_regions;
Expand Down Expand Up @@ -351,7 +351,7 @@ start_linear_scan:
do
{
// Is this index stale?
BOOST_MONAD_AUTO(ondisk_index_info, find_last_good_ondisk_index(rwh));
BOOST_OUTCOME_AUTO(ondisk_index_info, find_last_good_ondisk_index(rwh));
if(ondisk_index_info.offset!=offset_loaded_from)
{
// A better conflict resolution strategy might check to see if deltas
Expand Down Expand Up @@ -394,7 +394,7 @@ start_linear_scan:
//]
//[workshop_final5]
// Reloads the index if needed
monad<void> refresh(afio::handle_ptr h) noexcept
outcome<void> refresh(afio::handle_ptr h) noexcept
{
static afio::off_t last_size;
error_code ec;
Expand Down Expand Up @@ -595,7 +595,7 @@ shared_future<data_store::istream> data_store::lookup(std::string name) noexcept
{
try
{
BOOST_MONAD_PROPAGATE(_index->refresh(_index_store));
BOOST_OUTCOME_PROPAGATE(_index->refresh(_index_store));
auto it=_index->key_to_region.find(name);
if(_index->key_to_region.end()==it)
return error_code(ENOENT, generic_category()); // not found
Expand All @@ -607,7 +607,7 @@ shared_future<data_store::istream> data_store::lookup(std::string name) noexcept
// When the read completes call this continuation
return h.then([buffer, length](const afio::future<> &h) -> shared_future<data_store::istream> {
// If read failed, return the error or exception immediately
BOOST_MONAD_PROPAGATE(h);
BOOST_OUTCOME_PROPAGATE(h);
data_store::istream ret(std::make_shared<idirectstream>(h.get_handle(), buffer, (size_t) length));
return ret;
});
Expand All @@ -618,7 +618,7 @@ shared_future<data_store::istream> data_store::lookup(std::string name) noexcept
}
}

monad<data_store::ostream> data_store::write(std::string name) noexcept
outcome<data_store::ostream> data_store::write(std::string name) noexcept
{
try
{
Expand Down
16 changes: 8 additions & 8 deletions example/workshop_naive.ipp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//[workshop_naive_interface
namespace filesystem = BOOST_AFIO_V2_NAMESPACE::filesystem;
using BOOST_MONAD_V1_NAMESPACE::monad;
using BOOST_OUTCOME_V1_NAMESPACE::outcome;

class data_store
{
Expand All @@ -12,9 +12,9 @@ public:
// Type used for write streams
using ostream = std::shared_ptr<std::ostream>;
// Type used for lookup
using lookup_result_type = monad<istream>;
using lookup_result_type = outcome<istream>;
// Type used for write
using write_result_type = monad<ostream>;
using write_result_type = outcome<ostream>;

// Disposition flags
static constexpr size_t writeable = (1<<0);
Expand All @@ -23,14 +23,14 @@ public:
data_store(size_t flags = 0, filesystem::path path = "store");

// Look up item named name for reading, returning a std::istream for the item if it exists
monad<istream> lookup(std::string name) noexcept;
outcome<istream> lookup(std::string name) noexcept;
// Look up item named name for writing, returning an ostream for that item
monad<ostream> write(std::string name) noexcept;
outcome<ostream> write(std::string name) noexcept;
};
//]

//[workshop_naive]
using BOOST_MONAD_V1_NAMESPACE::empty;
using BOOST_OUTCOME_V1_NAMESPACE::empty;
using BOOST_AFIO_V2_NAMESPACE::error_code;
using BOOST_AFIO_V2_NAMESPACE::generic_category;

Expand All @@ -53,7 +53,7 @@ data_store::data_store(size_t flags, filesystem::path path) : _store_path(std::m
{
}

monad<data_store::istream> data_store::lookup(std::string name) noexcept
outcome<data_store::istream> data_store::lookup(std::string name) noexcept
{
if(!is_valid_name(name))
return error_code(EINVAL, generic_category());
Expand All @@ -70,7 +70,7 @@ monad<data_store::istream> data_store::lookup(std::string name) noexcept
}
}

monad<data_store::ostream> data_store::write(std::string name) noexcept
outcome<data_store::ostream> data_store::write(std::string name) noexcept
{
if(!_writeable)
return error_code(EROFS, generic_category());
Expand Down

0 comments on commit d29a2d7

Please sign in to comment.