Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions doc/modules/ROOT/pages/3.tutorials/3c.dns-lookup.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ capy::task<void> do_lookup(

== Understanding Results

The resolver returns a `resolver_results` object containing `resolver_entry`
elements. Each entry provides:
The resolver returns a `resolver_results` — an alias for
`std::vector<resolver_entry>` — containing one `resolver_entry` per resolved
endpoint. Each entry provides:

* `get_endpoint()` — The resolved endpoint (address + port)
* `host_name()` — The queried hostname
Expand Down
34 changes: 16 additions & 18 deletions doc/modules/ROOT/pages/4.guide/4j.resolver.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,14 @@ auto [ec, results] = co_await r.resolve("127.0.0.1", "8080", flags);

== Working with Results

The `resolver_results` class is a range of `resolver_entry` objects:
`resolver_results` is an alias for `std::vector<resolver_entry>`, so it
supports the full `std::vector` interface (iteration, `size()`, `empty()`,
indexing, and so on):

[source,cpp]
----
using resolver_results = std::vector<resolver_entry>;
----

[source,cpp]
----
Expand All @@ -134,23 +141,14 @@ for (auto const& entry : results)
}
----

=== resolver_results Interface

[source,cpp]
----
class resolver_results
{
public:
using iterator = /* ... */;
using const_iterator = /* ... */;

std::size_t size() const;
bool empty() const;

const_iterator begin() const;
const_iterator end() const;
};
----
[NOTE]
====
Copying a `resolver_results` deep-copies every entry, and each entry owns
two `std::string` query names. When handing the results to a sink that
takes the range by value — such as `corosio::connect` — pass an rvalue
(`std::move(results)`) or use the iterator-based overload
(`connect(s, results.begin(), results.end())`) to avoid the copy.
====

=== resolver_entry Interface

Expand Down
9 changes: 8 additions & 1 deletion include/boost/corosio/connect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ connect(Socket& s, Iter begin, Iter end, ConnectCondition cond);
@param endpoints A range of candidate endpoints. Taken by value
so temporaries (e.g. `resolver_results` returned from
`resolver::resolve`) remain alive for the coroutine's lifetime.
Because the range is owned by the coroutine, passing an lvalue
copies it; since `resolver_results` is a
`std::vector<resolver_entry>`, that is a deep copy of every entry.
Pass an rvalue (`std::move(results)`) or use the iterator overload
(`connect(s, results.begin(), results.end())`) to avoid the copy.

@return An awaitable completing with
`capy::io_result<typename Socket::endpoint_type>`:
Expand Down Expand Up @@ -153,7 +158,9 @@ connect(Socket& s, Range endpoints)

@param s The socket to connect. See the non-condition overload for
requirements.
@param endpoints A range of candidate endpoints.
@param endpoints A range of candidate endpoints, taken by value. See
the non-condition overload for the deep-copy caveat when passing
an lvalue `resolver_results`.
@param cond A predicate invocable with
`(std::error_code const&, typename Socket::endpoint_type const&)`
returning a value contextually convertible to `bool`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2026 Steve Gerbino
// Copyright (c) 2026 Michael Vandeberg
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -203,7 +204,7 @@ convert_results(
}
}

return resolver_results(std::move(entries));
return entries;
}

} // namespace resolver_detail
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2026 Steve Gerbino
// Copyright (c) 2026 Michael Vandeberg
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -161,7 +162,7 @@ posix_resolver_detail::convert_results(
}
}

return resolver_results(std::move(entries));
return entries;
}

inline std::error_code
Expand Down
4 changes: 4 additions & 0 deletions include/boost/corosio/native/native_resolver.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2026 Steve Gerbino
// Copyright (c) 2026 Michael Vandeberg
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -191,6 +192,9 @@ class native_resolver : public resolver
@param service The service name or port string.

@return An awaitable yielding `io_result<resolver_results>`.

@note `resolver_results` is an alias for `std::vector<resolver_entry>`;
copying it deep-copies every entry. See @ref resolver::resolve.
*/
auto resolve(std::string_view host, std::string_view service)
{
Expand Down
6 changes: 6 additions & 0 deletions include/boost/corosio/resolver.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2026 Steve Gerbino
// Copyright (c) 2026 Michael Vandeberg
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -351,6 +352,11 @@ class BOOST_COROSIO_DECL resolver : public io_object

@return An awaitable that completes with `io_result<resolver_results>`.

@note `resolver_results` is an alias for `std::vector<resolver_entry>`.
Copying it deep-copies every entry (each owns two `std::string`s);
move it (`std::move(results)`) or pass iterators when handing it to
a by-value sink such as @ref connect.

@par Example
@code
auto [ec, results] = co_await r.resolve("www.example.com", "https");
Expand Down
119 changes: 12 additions & 107 deletions include/boost/corosio/resolver_results.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2026 Michael Vandeberg
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -13,8 +14,6 @@
#include <boost/corosio/detail/config.hpp>
#include <boost/corosio/endpoint.hpp>

#include <cstddef>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
Expand Down Expand Up @@ -80,115 +79,21 @@ class resolver_entry

/** A range of entries produced by a resolver.

This class holds the results of a DNS resolution query.
It provides a range interface for iterating over the
resolved endpoints.
This is an alias for `std::vector<resolver_entry>`: a contiguous,
owning range of the endpoints resolved by a query. It supports the
full `std::vector` interface (iteration, `size()`, `empty()`, etc.).

@note Copying a `resolver_results` deep-copies every entry, and each
entry owns two `std::string`s (the host and service names). When you
want to hand a result to a sink that takes the range by value — such
as `corosio::connect` — pass an rvalue (`std::move(results)`) or use
the iterator-based `connect` overloads to avoid the copy.

@par Thread Safety
Distinct objects: Safe.@n
Shared objects: Safe (immutable after construction).
Shared objects: Unsafe.
*/
class resolver_results
{
public:
/// The entry type.
using value_type = resolver_entry;

/// Const reference to an entry.
using const_reference = value_type const&;

/// Reference to an entry (always const).
using reference = const_reference;

/// Const iterator over entries.
using const_iterator = std::vector<resolver_entry>::const_iterator;

/// Iterator over entries (always const).
using iterator = const_iterator;

/// Signed difference type.
using difference_type = std::ptrdiff_t;

/// Unsigned size type.
using size_type = std::size_t;

private:
std::shared_ptr<std::vector<resolver_entry>> entries_;

public:
/// Construct an empty results range.
resolver_results() = default;

/** Construct from a vector of entries.

@param entries The resolved entries.
*/
explicit resolver_results(std::vector<resolver_entry> entries)
: entries_(
std::make_shared<std::vector<resolver_entry>>(std::move(entries)))
{
}

/// Return the number of entries.
size_type size() const noexcept
{
return entries_ ? entries_->size() : 0;
}

/// Check if the results are empty.
bool empty() const noexcept
{
return !entries_ || entries_->empty();
}

/// Return an iterator to the first entry.
const_iterator begin() const noexcept
{
if (entries_)
return entries_->begin();
return std::vector<resolver_entry>::const_iterator();
}

/// Return an iterator past the last entry.
const_iterator end() const noexcept
{
if (entries_)
return entries_->end();
return std::vector<resolver_entry>::const_iterator();
}

/// Return an iterator to the first entry.
const_iterator cbegin() const noexcept
{
return begin();
}

/// Return an iterator past the last entry.
const_iterator cend() const noexcept
{
return end();
}

/// Swap with another results object.
void swap(resolver_results& other) noexcept
{
entries_.swap(other.entries_);
}

/// Test for equality.
friend bool
operator==(resolver_results const& a, resolver_results const& b) noexcept
{
return a.entries_ == b.entries_;
}

/// Test for inequality.
friend bool
operator!=(resolver_results const& a, resolver_results const& b) noexcept
{
return !(a == b);
}
};
using resolver_results = std::vector<resolver_entry>;

/** The result of a reverse DNS resolution.

Expand Down
Loading