Browse Source

Update hylia (link) sources, now builds with mingw

tags/v2.1-rc1
falkTX 6 years ago
parent
commit
cabb3f6c79
100 changed files with 8095 additions and 4787 deletions
  1. +4
    -5
      source/Makefile.mk
  2. +30
    -0
      source/modules/hylia/hylia.cpp
  3. +4
    -0
      source/modules/hylia/hylia.h
  4. +67
    -25
      source/modules/hylia/link/AudioEngine.cpp
  5. +26
    -3
      source/modules/hylia/link/AudioEngine.hpp
  6. +128
    -68
      source/modules/hylia/link/ableton/Link.hpp
  7. +125
    -64
      source/modules/hylia/link/ableton/Link.ipp
  8. +2
    -2
      source/modules/hylia/link/ableton/discovery/IpV4Interface.hpp
  9. +80
    -30
      source/modules/hylia/link/ableton/discovery/NetworkByteStreamSerializable.hpp
  10. +1
    -0
      source/modules/hylia/link/ableton/discovery/Payload.hpp
  11. +4
    -6
      source/modules/hylia/link/ableton/discovery/PeerGateway.hpp
  12. +0
    -139
      source/modules/hylia/link/ableton/discovery/Socket.hpp
  13. +1
    -1
      source/modules/hylia/link/ableton/discovery/UdpMessenger.hpp
  14. +2
    -2
      source/modules/hylia/link/ableton/discovery/test/Interface.hpp
  15. +43
    -8
      source/modules/hylia/link/ableton/discovery/test/PayloadEntries.hpp
  16. +3
    -1
      source/modules/hylia/link/ableton/discovery/test/Socket.hpp
  17. +6
    -26
      source/modules/hylia/link/ableton/link/CircularFifo.hpp
  18. +2
    -2
      source/modules/hylia/link/ableton/link/ClientSessionTimelines.hpp
  19. +376
    -115
      source/modules/hylia/link/ableton/link/Controller.hpp
  20. +5
    -6
      source/modules/hylia/link/ableton/link/Gateway.hpp
  21. +36
    -63
      source/modules/hylia/link/ableton/link/Measurement.hpp
  22. +2
    -4
      source/modules/hylia/link/ableton/link/MeasurementEndpointV4.hpp
  23. +23
    -36
      source/modules/hylia/link/ableton/link/MeasurementService.hpp
  24. +17
    -10
      source/modules/hylia/link/ableton/link/NodeState.hpp
  25. +97
    -0
      source/modules/hylia/link/ableton/link/Optional.hpp
  26. +7
    -13
      source/modules/hylia/link/ableton/link/PayloadEntries.hpp
  27. +5
    -0
      source/modules/hylia/link/ableton/link/PeerState.hpp
  28. +54
    -12
      source/modules/hylia/link/ableton/link/Peers.hpp
  29. +2
    -2
      source/modules/hylia/link/ableton/link/Phase.hpp
  30. +20
    -23
      source/modules/hylia/link/ableton/link/PingResponder.hpp
  31. +2
    -4
      source/modules/hylia/link/ableton/link/SessionId.hpp
  32. +80
    -0
      source/modules/hylia/link/ableton/link/SessionState.hpp
  33. +3
    -2
      source/modules/hylia/link/ableton/link/Sessions.hpp
  34. +123
    -0
      source/modules/hylia/link/ableton/link/StartStopState.hpp
  35. +2
    -4
      source/modules/hylia/link/ableton/link/Timeline.hpp
  36. +11
    -14
      source/modules/hylia/link/ableton/platforms/Config.hpp
  37. +0
    -105
      source/modules/hylia/link/ableton/platforms/asio/AsioService.hpp
  38. +19
    -12
      source/modules/hylia/link/ableton/platforms/asio/AsioWrapper.hpp
  39. +2
    -2
      source/modules/hylia/link/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp
  40. +3
    -3
      source/modules/hylia/link/ableton/platforms/asio/Util.hpp
  41. +0
    -10
      source/modules/hylia/link/ableton/platforms/linux/Clock.hpp
  42. +1
    -1
      source/modules/hylia/link/ableton/platforms/posix/ScanIpIfAddrs.hpp
  43. +1
    -1
      source/modules/hylia/link/ableton/platforms/windows/ScanIpIfAddrs.hpp
  44. +3
    -6
      source/modules/hylia/link/ableton/test/CatchWrapper.hpp
  45. +0
    -83
      source/modules/hylia/link/ableton/test/serial_io/Socket.hpp
  46. +2
    -2
      source/modules/hylia/link/ableton/util/SampleTiming.hpp
  47. +20
    -17
      source/modules/hylia/link/asio.hpp
  48. +9
    -1
      source/modules/hylia/link/asio/associated_allocator.hpp
  49. +8
    -1
      source/modules/hylia/link/asio/associated_executor.hpp
  50. +275
    -44
      source/modules/hylia/link/asio/async_result.hpp
  51. +123
    -0
      source/modules/hylia/link/asio/awaitable.hpp
  52. +320
    -150
      source/modules/hylia/link/asio/basic_datagram_socket.hpp
  53. +194
    -49
      source/modules/hylia/link/asio/basic_deadline_timer.hpp
  54. +20
    -4
      source/modules/hylia/link/asio/basic_io_object.hpp
  55. +322
    -151
      source/modules/hylia/link/asio/basic_raw_socket.hpp
  56. +240
    -89
      source/modules/hylia/link/asio/basic_seq_packet_socket.hpp
  57. +273
    -93
      source/modules/hylia/link/asio/basic_serial_port.hpp
  58. +217
    -62
      source/modules/hylia/link/asio/basic_signal_set.hpp
  59. +426
    -169
      source/modules/hylia/link/asio/basic_socket.hpp
  60. +934
    -290
      source/modules/hylia/link/asio/basic_socket_acceptor.hpp
  61. +127
    -45
      source/modules/hylia/link/asio/basic_socket_iostream.hpp
  62. +357
    -316
      source/modules/hylia/link/asio/basic_socket_streambuf.hpp
  63. +264
    -119
      source/modules/hylia/link/asio/basic_stream_socket.hpp
  64. +4
    -5
      source/modules/hylia/link/asio/basic_streambuf.hpp
  65. +1
    -1
      source/modules/hylia/link/asio/basic_streambuf_fwd.hpp
  66. +197
    -95
      source/modules/hylia/link/asio/basic_waitable_timer.hpp
  67. +20
    -18
      source/modules/hylia/link/asio/bind_executor.hpp
  68. +1081
    -1312
      source/modules/hylia/link/asio/buffer.hpp
  69. +6
    -28
      source/modules/hylia/link/asio/buffered_read_stream.hpp
  70. +1
    -1
      source/modules/hylia/link/asio/buffered_read_stream_fwd.hpp
  71. +4
    -20
      source/modules/hylia/link/asio/buffered_stream.hpp
  72. +1
    -1
      source/modules/hylia/link/asio/buffered_stream_fwd.hpp
  73. +6
    -28
      source/modules/hylia/link/asio/buffered_write_stream.hpp
  74. +1
    -1
      source/modules/hylia/link/asio/buffered_write_stream_fwd.hpp
  75. +52
    -12
      source/modules/hylia/link/asio/buffers_iterator.hpp
  76. +88
    -0
      source/modules/hylia/link/asio/co_spawn.hpp
  77. +1
    -1
      source/modules/hylia/link/asio/completion_condition.hpp
  78. +136
    -0
      source/modules/hylia/link/asio/compose.hpp
  79. +96
    -96
      source/modules/hylia/link/asio/connect.hpp
  80. +7
    -7
      source/modules/hylia/link/asio/coroutine.hpp
  81. +0
    -438
      source/modules/hylia/link/asio/datagram_socket_service.hpp
  82. +1
    -1
      source/modules/hylia/link/asio/deadline_timer.hpp
  83. +0
    -170
      source/modules/hylia/link/asio/deadline_timer_service.hpp
  84. +11
    -1
      source/modules/hylia/link/asio/defer.hpp
  85. +62
    -0
      source/modules/hylia/link/asio/detached.hpp
  86. +1
    -1
      source/modules/hylia/link/asio/detail/array.hpp
  87. +1
    -1
      source/modules/hylia/link/asio/detail/array_fwd.hpp
  88. +1
    -1
      source/modules/hylia/link/asio/detail/assert.hpp
  89. +1
    -1
      source/modules/hylia/link/asio/detail/atomic_count.hpp
  90. +4
    -3
      source/modules/hylia/link/asio/detail/base_from_completion_cond.hpp
  91. +358
    -1
      source/modules/hylia/link/asio/detail/bind_handler.hpp
  92. +1
    -1
      source/modules/hylia/link/asio/detail/buffer_resize_guard.hpp
  93. +185
    -19
      source/modules/hylia/link/asio/detail/buffer_sequence_adapter.hpp
  94. +1
    -1
      source/modules/hylia/link/asio/detail/buffered_stream_storage.hpp
  95. +1
    -1
      source/modules/hylia/link/asio/detail/call_stack.hpp
  96. +4
    -4
      source/modules/hylia/link/asio/detail/chrono.hpp
  97. +1
    -1
      source/modules/hylia/link/asio/detail/chrono_time_traits.hpp
  98. +1
    -1
      source/modules/hylia/link/asio/detail/completion_handler.hpp
  99. +94
    -0
      source/modules/hylia/link/asio/detail/concurrency_hint.hpp
  100. +112
    -0
      source/modules/hylia/link/asio/detail/conditionally_enabled_event.hpp

+ 4
- 5
source/Makefile.mk View File

@@ -119,7 +119,7 @@ endif

ifeq ($(NOOPT),true)
# No CPU-specific optimization flags
BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections
BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections -DBUILDING_CARLA_NOOPT
endif

ifeq ($(WIN32),true)
@@ -218,10 +218,9 @@ HAVE_HYLIA = true
endif
endif

# FIXME make mingw compatible
# ifeq ($(WIN32),true)
# HAVE_HYLIA = true
# endif
ifeq ($(WIN32),true)
HAVE_HYLIA = true
endif

ifeq ($(MACOS_OR_WIN32),true)
HAVE_DGL = true


+ 30
- 0
source/modules/hylia/hylia.cpp View File

@@ -64,6 +64,21 @@ public:
outputLatency = latency;
}

void setStartStopSyncEnabled(const bool enabled)
{
engine.setStartStopSyncEnabled(enabled);
}

void startPlaying()
{
engine.startPlaying();
}

void stopPlaying()
{
engine.stopPlaying();
}

void process(const uint32_t frames, LinkTimeInfo* const info)
{
const std::chrono::microseconds hostTime = hostTimeFilter.sampleTimeToHostTime(sampleTime)
@@ -114,6 +129,21 @@ void hylia_set_output_latency(hylia_t* link, uint32_t latency)
((HyliaTransport*)link)->setOutputLatency(latency);
}

void hylia_set_start_stop_sync_enabled(hylia_t* link, bool enabled)
{
((HyliaTransport*)link)->setStartStopSyncEnabled(enabled);
}

void hylia_start_playing(hylia_t* link)
{
((HyliaTransport*)link)->startPlaying();
}

void hylia_stop_playing(hylia_t* link)
{
((HyliaTransport*)link)->stopPlaying();
}

void hylia_process(hylia_t* link, uint32_t frames, hylia_time_info_t* info)
{
((HyliaTransport*)link)->process(frames, (LinkTimeInfo*)info);


+ 4
- 0
source/modules/hylia/hylia.h View File

@@ -30,6 +30,7 @@ typedef struct _hylia_t hylia_t;

typedef struct _hylia_time_info_t {
double beatsPerBar, beatsPerMinute, beat, phase;
bool playing;
} hylia_time_info_t;

hylia_t* hylia_create(void);
@@ -38,6 +39,9 @@ void hylia_process(hylia_t* link, uint32_t frames, hylia_time_info_t* info);
void hylia_set_beats_per_bar(hylia_t* link, double beatsPerBar);
void hylia_set_beats_per_minute(hylia_t* link, double beatsPerMinute);
void hylia_set_output_latency(hylia_t* link, uint32_t latency);
void hylia_set_start_stop_sync_enabled(hylia_t* link, bool enabled);
void hylia_start_playing(hylia_t* link);
void hylia_stop_playing(hylia_t* link);
void hylia_cleanup(hylia_t* link);

#ifdef __cplusplus


+ 67
- 25
source/modules/hylia/link/AudioEngine.cpp View File

@@ -19,10 +19,6 @@

#include "AudioEngine.hpp"

// Make sure to define this before <cmath> is included for Windows
#define _USE_MATH_DEFINES
#include <cmath>

namespace ableton
{
namespace link
@@ -30,19 +26,38 @@ namespace link

AudioEngine::AudioEngine(Link& link)
: mLink(link)
, mSharedEngineData({0., false, 4.})
, mSharedEngineData({0., false, false, 4., false})
, mLockfreeEngineData(mSharedEngineData)
, mIsPlaying(false)
{
}

void AudioEngine::startPlaying()
{
std::lock_guard<std::mutex> lock(mEngineDataGuard);
mSharedEngineData.requestStart = true;
}

void AudioEngine::stopPlaying()
{
std::lock_guard<std::mutex> lock(mEngineDataGuard);
mSharedEngineData.requestStop = true;
}

bool AudioEngine::isPlaying() const
{
return mLink.captureAppSessionState().isPlaying();
}

double AudioEngine::beatTime() const
{
const auto timeline = mLink.captureAppTimeline();
return timeline.beatAtTime(mLink.clock().micros(), mSharedEngineData.quantum);
const auto sessionState = mLink.captureAppSessionState();
return sessionState.beatAtTime(mLink.clock().micros(), mSharedEngineData.quantum);
}

void AudioEngine::setTempo(double tempo)
{
const std::lock_guard<std::mutex> lock(mEngineDataGuard);
std::lock_guard<std::mutex> lock(mEngineDataGuard);
mSharedEngineData.requestedTempo = tempo;
}

@@ -53,26 +68,38 @@ double AudioEngine::quantum() const

void AudioEngine::setQuantum(double quantum)
{
const std::lock_guard<std::mutex> lock(mEngineDataGuard);
std::lock_guard<std::mutex> lock(mEngineDataGuard);
mSharedEngineData.quantum = quantum;
mSharedEngineData.resetBeatTime = true;
}

bool AudioEngine::isStartStopSyncEnabled() const
{
return mLink.isStartStopSyncEnabled();
}

void AudioEngine::setStartStopSyncEnabled(const bool enabled)
{
mLink.enableStartStopSync(enabled);
}

AudioEngine::EngineData AudioEngine::pullEngineData()
{
auto engineData = EngineData{};

if (mEngineDataGuard.try_lock())
{
engineData.requestedTempo = mSharedEngineData.requestedTempo;
mSharedEngineData.requestedTempo = 0;
engineData.requestStart = mSharedEngineData.requestStart;
mSharedEngineData.requestStart = false;
engineData.requestStop = mSharedEngineData.requestStop;
mSharedEngineData.requestStop = false;

engineData.resetBeatTime = mSharedEngineData.resetBeatTime;
engineData.quantum = mSharedEngineData.quantum;
mSharedEngineData.resetBeatTime = false;
mLockfreeEngineData.quantum = mSharedEngineData.quantum;
mLockfreeEngineData.startStopSyncOn = mSharedEngineData.startStopSyncOn;

mEngineDataGuard.unlock();
}
engineData.quantum = mLockfreeEngineData.quantum;

return engineData;
}
@@ -81,29 +108,44 @@ void AudioEngine::timelineCallback(const std::chrono::microseconds hostTime, Lin
{
const auto engineData = pullEngineData();

auto timeline = mLink.captureAudioTimeline();
auto sessionState = mLink.captureAudioSessionState();

if (engineData.requestStart)
{
sessionState.setIsPlaying(true, hostTime);
}

if (engineData.requestStop)
{
sessionState.setIsPlaying(false, hostTime);
}

if (engineData.resetBeatTime)
if (!mIsPlaying && sessionState.isPlaying())
{
// Reset the timeline so that beat 0 corresponds to the time when transport starts
sessionState.requestBeatAtStartPlayingTime(0, engineData.quantum);
mIsPlaying = true;
}
else if (mIsPlaying && !sessionState.isPlaying())
{
// Reset the timeline so that beat 0 lands at the beginning of
// this buffer and clear the flag.
timeline.requestBeatAtTime(0, hostTime, engineData.quantum);
mIsPlaying = false;
}

if (engineData.requestedTempo > 0)
{
// Set the newly requested tempo from the beginning of this buffer
timeline.setTempo(engineData.requestedTempo, hostTime);
sessionState.setTempo(engineData.requestedTempo, hostTime);
}

// Timeline modifications are complete, commit the results
mLink.commitAudioTimeline(timeline);
mLink.commitAudioSessionState(sessionState);

// Save timeline info
// Save session state
info->beatsPerBar = engineData.quantum;
info->beatsPerMinute = timeline.tempo();
info->beat = timeline.beatAtTime(hostTime, engineData.quantum);
info->phase = timeline.phaseAtTime(hostTime, engineData.quantum);
info->beatsPerMinute = sessionState.tempo();
info->beat = sessionState.beatAtTime(hostTime, engineData.quantum);
info->phase = sessionState.phaseAtTime(hostTime, engineData.quantum);
info->playing = mIsPlaying;
}

} // namespace link


+ 26
- 3
source/modules/hylia/link/AudioEngine.hpp View File

@@ -19,13 +19,27 @@

#pragma once

// Make sure to define this before <cmath> is included for Windows
#ifdef LINK_PLATFORM_WINDOWS
#define _USE_MATH_DEFINES
#include "mingw-std-threads/mingw.condition_variable.h"
#include "mingw-std-threads/mingw.mutex.h"
#include "mingw-std-threads/mingw.thread.h"
#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl(((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl(((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif
#endif

#include <cmath>

#include "ableton/Link.hpp"
#include <mutex>

struct LinkTimeInfo {
double beatsPerBar, beatsPerMinute, beat, phase;
bool playing;
};

namespace ableton
@@ -37,10 +51,15 @@ class AudioEngine
{
public:
AudioEngine(Link& link);
void startPlaying();
void stopPlaying();
bool isPlaying() const;
double beatTime() const;
void setTempo(double tempo);
double quantum() const;
void setQuantum(double quantum);
bool isStartStopSyncEnabled() const;
void setStartStopSyncEnabled(bool enabled);

void timelineCallback(const std::chrono::microseconds hostTime, LinkTimeInfo* const info);

@@ -48,14 +67,18 @@ private:
struct EngineData
{
double requestedTempo;
bool resetBeatTime;
bool requestStart;
bool requestStop;
double quantum;
bool startStopSyncOn;
};

EngineData pullEngineData();

Link& mLink;
EngineData mSharedEngineData;
EngineData mLockfreeEngineData;
bool mIsPlaying;
std::mutex mEngineDataGuard;
};



+ 128
- 68
source/modules/hylia/link/ableton/Link.hpp View File

@@ -32,13 +32,20 @@ namespace ableton
/*! @class Link
* @brief Class that represents a participant in a Link session.
*
* @discussion Each Link instance has its own beat timeline that
* starts running from beat 0 at the initial tempo when
* constructed. A Link instance is initially disabled after
* construction, which means that it will not communicate on the
* network. Once enabled, a Link instance initiates network
* communication in an effort to discover other peers. When peers are
* discovered, they immediately become part of a shared Link session.
* @discussion Each Link instance has its own session state which
* represents a beat timeline and a transport start/stop state. The
* timeline starts running from beat 0 at the initial tempo when
* constructed. The timeline always advances at a speed defined by
* its current tempo, even if transport is stopped. Synchronizing to the
* transport start/stop state of Link is optional for every peer.
* The transport start/stop state is only shared with other peers when
* start/stop synchronization is enabled.
*
* A Link instance is initially disabled after construction, which
* means that it will not communicate on the network. Once enabled,
* a Link instance initiates network communication in an effort to
* discover other peers. When peers are discovered, they immediately
* become part of a shared Link session.
*
* Each method of the Link type documents its thread-safety and
* realtime-safety properties. When a method is marked thread-safe,
@@ -47,31 +54,31 @@ namespace ableton
* it does not block and is appropriate for use in the thread that
* performs audio IO.
*
* Link provides one Timeline capture/commit method pair for use in the
* audio thread and one for all other application contexts. In
* general, modifying the Link timeline should be done in the audio
* Link provides one session state capture/commit method pair for use
* in the audio thread and one for all other application contexts. In
* general, modifying the session state should be done in the audio
* thread for the most accurate timing results. The ability to modify
* the Link timeline from application threads should only be used in
* the session state from application threads should only be used in
* cases where an application's audio thread is not actively running
* or if it doesn't generate audio at all. Modifying the Link
* timeline from both the audio thread and an application thread
* concurrently is not advised and will potentially lead to
* unexpected behavior.
* or if it doesn't generate audio at all. Modifying the Link session
* state from both the audio thread and an application thread
* concurrently is not advised and will potentially lead to unexpected
* behavior.
*/
template <typename Clock>
class BasicLink
class Link
{
public:
class Timeline;
using Clock = link::platform::Clock;
class SessionState;

/*! @brief Construct with an initial tempo. */
BasicLink(double bpm);
Link(double bpm);

/*! @brief Link instances cannot be copied or moved */
BasicLink(const BasicLink<Clock>&) = delete;
BasicLink& operator=(const BasicLink<Clock>&) = delete;
BasicLink(BasicLink<Clock>&&) = delete;
BasicLink& operator=(BasicLink<Clock>&&) = delete;
Link(const Link&) = delete;
Link& operator=(const Link&) = delete;
Link(Link&&) = delete;
Link& operator=(Link&&) = delete;

/*! @brief Is Link currently enabled?
* Thread-safe: yes
@@ -85,6 +92,18 @@ public:
*/
void enable(bool bEnable);

/*! @brief: Is start/stop synchronization enabled?
* Thread-safe: yes
* Realtime-safe: no
*/
bool isStartStopSyncEnabled() const;

/*! @brief: Enable start/stop synchronization.
* Thread-safe: yes
* Realtime-safe: no
*/
void enableStartStopSync(bool bEnable);

/*! @brief How many peers are currently connected in a Link session?
* Thread-safe: yes
* Realtime-safe: yes
@@ -116,6 +135,19 @@ public:
template <typename Callback>
void setTempoCallback(Callback callback);

/*! brief: Register a callback to be notified when the state of
* start/stop isPlaying changes.
* Thread-safe: yes
* Realtime-safe: no
*
* @discussion The callback is invoked on a Link-managed thread.
*
* @param callback The callback signature is:
* void (bool isPlaying)
*/
template <typename Callback>
void setStartStopCallback(Callback callback);

/*! @brief The clock used by Link.
* Thread-safe: yes
* Realtime-safe: yes
@@ -130,69 +162,81 @@ public:
*/
Clock clock() const;

/*! @brief Capture the current Link timeline from the audio thread.
/*! @brief Capture the current Link Session State from the audio thread.
* Thread-safe: no
* Realtime-safe: yes
*
* @discussion This method should ONLY be called in the audio thread
* and must not be accessed from any other threads. The returned
* Timeline stores a snapshot of the current Link state, so it
* object stores a snapshot of the current Link Session State, so it
* should be captured and used in a local scope. Storing the
* Timeline for later use in a different context is not advised
* because it will provide an outdated view on the Link state.
* Session State for later use in a different context is not advised
* because it will provide an outdated view.
*/
Timeline captureAudioTimeline() const;
SessionState captureAudioSessionState() const;

/*! @brief Commit the given timeline to the Link session from the
/*! @brief Commit the given Session State to the Link session from the
* audio thread.
* Thread-safe: no
* Realtime-safe: yes
*
* @discussion This method should ONLY be called in the audio
* thread. The given timeline will replace the current Link
* timeline. Modifications to the session based on the new timeline
* will be communicated to other peers in the session.
* thread. The given Session State will replace the current Link
* state. Modifications will be communicated to other peers in the
* session.
*/
void commitAudioTimeline(Timeline timeline);
void commitAudioSessionState(SessionState state);

/*! @brief Capture the current Link timeline from an application
/*! @brief Capture the current Link Session State from an application
* thread.
* Thread-safe: yes
* Realtime-safe: no
*
* @discussion Provides a mechanism for capturing the Link timeline
* from an application thread (other than the audio thread). The
* returned Timeline stores a snapshot of the current Link state,
* so it should be captured and used in a local scope. Storing the
* Timeline for later use in a different context is not advised
* because it will provide an outdated view on the Link state.
* @discussion Provides a mechanism for capturing the Link Session
* State from an application thread (other than the audio thread).
* The returned Session State stores a snapshot of the current Link
* state, so it should be captured and used in a local scope.
* Storing the it for later use in a different context is not
* advised because it will provide an outdated view.
*/
Timeline captureAppTimeline() const;
SessionState captureAppSessionState() const;

/*! @brief Commit the given timeline to the Link session from an
/*! @brief Commit the given Session State to the Link session from an
* application thread.
* Thread-safe: yes
* Realtime-safe: no
*
* @discussion The given timeline will replace the current Link
* timeline. Modifications to the session based on the new timeline
* will be communicated to other peers in the session.
* @discussion The given Session State will replace the current Link
* Session State. Modifications of the Session State will be
* communicated to other peers in the session.
*/
void commitAppTimeline(Timeline timeline);
void commitAppSessionState(SessionState state);

/*! @class Timeline
* @brief Representation of a mapping between time and beats for
* varying quanta.
/*! @class SessionState
* @brief Representation of a timeline and the start/stop state
*
* @discussion A SessionState object is intended for use in a local scope within
* a single thread - none of its methods are thread-safe. All of its methods are
* non-blocking, so it is safe to use from a realtime thread.
* It provides functions to observe and manipulate the timeline and start/stop
* state.
*
* @discussion A Timeline object is intended for use in a local
* scope within a single thread - none of its methods are
* thread-safe. All of its methods are non-blocking, so it is safe
* to use from a realtime thread.
* The timeline is a representation of a mapping between time and beats for varying
* quanta.
* The start/stop state represents the user intention to start or stop transport at
* a specific time. Start stop synchronization is an optional feature that allows to
* share the user request to start or stop transport between a subgroup of peers in
* a Link session. When observing a change of start/stop state, audio playback of a
* peer should be started or stopped the same way it would have happened if the user
* had requested that change at the according time locally. The start/stop state can
* only be changed by the user. This means that the current local start/stop state
* persists when joining or leaving a Link session. After joining a Link session
* start/stop change requests will be communicated to all connected peers.
*/
class Timeline
class SessionState
{
public:
Timeline(const link::Timeline timeline, const bool bRespectQuantum);
SessionState(const link::ApiState state, const bool bRespectQuantum);

/*! @brief: The tempo of the timeline, in bpm */
double tempo() const;
@@ -286,29 +330,45 @@ public:
*/
void forceBeatAtTime(double beat, std::chrono::microseconds time, double quantum);

private:
friend BasicLink<Clock>;
/*! @brief: Set if transport should be playing or stopped, taking effect
* at the given time.
*/
void setIsPlaying(bool isPlaying, std::chrono::microseconds time);

/*! @brief: Is transport playing? */
bool isPlaying() const;

/*! @brief: Get the time at which a transport start/stop occurs */
std::chrono::microseconds timeForIsPlaying() const;

link::Timeline mOriginalTimeline;
/*! @brief: Convenience function to attempt to map the given beat to the time
* when transport is starting to play in context of the given quantum.
* This function evaluates to a no-op if isPlaying() equals false.
*/
void requestBeatAtStartPlayingTime(double beat, double quantum);

/*! @brief: Convenience function to start or stop transport at a given time and
* attempt to map the given beat to this time in context of the given quantum.
*/
void setIsPlayingAndRequestBeatAtTime(
bool isPlaying, std::chrono::microseconds time, double beat, double quantum);

private:
friend Link;
link::ApiState mOriginalState;
link::ApiState mState;
bool mbRespectQuantum;
link::Timeline mTimeline;
};

private:
using Controller = ableton::link::Controller<link::PeerCountCallback,
link::TempoCallback,
Clock,
link::platform::IoContext>;

std::mutex mCallbackMutex;
link::PeerCountCallback mPeerCountCallback;
link::TempoCallback mTempoCallback;
link::StartStopStateCallback mStartStopCallback;
Clock mClock;
Controller mController;
link::platform::Controller mController;
};

using Link = BasicLink<link::platform::Clock>;

} // ableton
} // namespace ableton

#include <ableton/Link.ipp>

+ 125
- 64
source/modules/hylia/link/ableton/Link.ipp View File

@@ -23,11 +23,40 @@

namespace ableton
{
namespace detail
{

inline Link::SessionState toSessionState(
const link::ClientState& state, const bool isConnected)
{
const auto time = state.timeline.fromBeats(state.startStopState.beats);
const auto startStopState =
link::ApiStartStopState{state.startStopState.isPlaying, time};
return {{state.timeline, startStopState}, isConnected};
}

template <typename Clock>
inline BasicLink<Clock>::BasicLink(const double bpm)
inline link::IncomingClientState toIncomingClientState(const link::ApiState& state,
const link::ApiState& originalState,
const std::chrono::microseconds timestamp)
{
const auto timeline = originalState.timeline != state.timeline
? link::OptionalTimeline{state.timeline}
: link::OptionalTimeline{};
const auto startStopState =
originalState.startStopState != state.startStopState
? link::OptionalStartStopState{{state.startStopState.isPlaying,
state.timeline.toBeats(state.startStopState.time), timestamp}}
: link::OptionalStartStopState{};
return {timeline, startStopState, timestamp};
}

} // namespace detail

inline Link::Link(const double bpm)
: mPeerCountCallback([](std::size_t) {})
, mTempoCallback([](link::Tempo) {})
, mStartStopCallback([](bool) {})
, mClock{}
, mController(link::Tempo(bpm),
[this](const std::size_t peers) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
@@ -37,134 +66,134 @@ inline BasicLink<Clock>::BasicLink(const double bpm)
std::lock_guard<std::mutex> lock(mCallbackMutex);
mTempoCallback(tempo);
},
[this](const bool isPlaying) {
std::lock_guard<std::mutex> lock(mCallbackMutex);
mStartStopCallback(isPlaying);
},
mClock,
util::injectVal(link::platform::IoContext{}))
{
}

template <typename Clock>
inline bool BasicLink<Clock>::isEnabled() const
inline bool Link::isEnabled() const
{
return mController.isEnabled();
}

template <typename Clock>
inline void BasicLink<Clock>::enable(const bool bEnable)
inline void Link::enable(const bool bEnable)
{
mController.enable(bEnable);
}

template <typename Clock>
inline std::size_t BasicLink<Clock>::numPeers() const
inline bool Link::isStartStopSyncEnabled() const
{
return mController.isStartStopSyncEnabled();
}

inline void Link::enableStartStopSync(bool bEnable)
{
mController.enableStartStopSync(bEnable);
}

inline std::size_t Link::numPeers() const
{
return mController.numPeers();
}

template <typename Clock>
template <typename Callback>
void BasicLink<Clock>::setNumPeersCallback(Callback callback)
void Link::setNumPeersCallback(Callback callback)
{
std::lock_guard<std::mutex> lock(mCallbackMutex);
mPeerCountCallback = [callback](const std::size_t numPeers) { callback(numPeers); };
}

template <typename Clock>
template <typename Callback>
void BasicLink<Clock>::setTempoCallback(Callback callback)
void Link::setTempoCallback(Callback callback)
{
std::lock_guard<std::mutex> lock(mCallbackMutex);
mTempoCallback = [callback](const link::Tempo tempo) { callback(tempo.bpm()); };
}

template <typename Clock>
inline Clock BasicLink<Clock>::clock() const
template <typename Callback>
void Link::setStartStopCallback(Callback callback)
{
std::lock_guard<std::mutex> lock(mCallbackMutex);
mStartStopCallback = callback;
}

inline Link::Clock Link::clock() const
{
return mClock;
}

template <typename Clock>
inline typename BasicLink<Clock>::Timeline BasicLink<Clock>::captureAudioTimeline() const
inline Link::SessionState Link::captureAudioSessionState() const
{
return BasicLink<Clock>::Timeline{mController.timelineRtSafe(), numPeers() > 0};
return detail::toSessionState(mController.clientStateRtSafe(), numPeers() > 0);
}

template <typename Clock>
inline void BasicLink<Clock>::commitAudioTimeline(const Timeline timeline)
inline void Link::commitAudioSessionState(const Link::SessionState state)
{
if (timeline.mOriginalTimeline != timeline.mTimeline)
{
mController.setTimelineRtSafe(timeline.mTimeline, mClock.micros());
}
mController.setClientStateRtSafe(
detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));
}

template <typename Clock>
inline typename BasicLink<Clock>::Timeline BasicLink<Clock>::captureAppTimeline() const
inline Link::SessionState Link::captureAppSessionState() const
{
return Timeline{mController.timeline(), numPeers() > 0};
return detail::toSessionState(mController.clientState(), numPeers() > 0);
}

template <typename Clock>
inline void BasicLink<Clock>::commitAppTimeline(const Timeline timeline)
inline void Link::commitAppSessionState(const Link::SessionState state)
{
if (timeline.mOriginalTimeline != timeline.mTimeline)
{
mController.setTimeline(timeline.mTimeline, mClock.micros());
}
mController.setClientState(
detail::toIncomingClientState(state.mState, state.mOriginalState, mClock.micros()));
}

////////////////////
// Link::Timeline //
////////////////////
// Link::SessionState

template <typename Clock>
inline BasicLink<Clock>::Timeline::Timeline(
const link::Timeline timeline, const bool bRespectQuantum)
: mOriginalTimeline(timeline)
inline Link::SessionState::SessionState(
const link::ApiState state, const bool bRespectQuantum)
: mOriginalState(state)
, mState(state)
, mbRespectQuantum(bRespectQuantum)
, mTimeline(timeline)
{
}

template <typename Clock>
inline double BasicLink<Clock>::Timeline::tempo() const
inline double Link::SessionState::tempo() const
{
return mTimeline.tempo.bpm();
return mState.timeline.tempo.bpm();
}

template <typename Clock>
inline void BasicLink<Clock>::Timeline::setTempo(
inline void Link::SessionState::setTempo(
const double bpm, const std::chrono::microseconds atTime)
{
const auto desiredTl =
link::clampTempo(link::Timeline{link::Tempo(bpm), mTimeline.toBeats(atTime), atTime});
mTimeline.tempo = desiredTl.tempo;
mTimeline.timeOrigin = desiredTl.fromBeats(mTimeline.beatOrigin);
const auto desiredTl = link::clampTempo(
link::Timeline{link::Tempo(bpm), mState.timeline.toBeats(atTime), atTime});
mState.timeline.tempo = desiredTl.tempo;
mState.timeline.timeOrigin = desiredTl.fromBeats(mState.timeline.beatOrigin);
}

template <typename Clock>
inline double BasicLink<Clock>::Timeline::beatAtTime(
inline double Link::SessionState::beatAtTime(
const std::chrono::microseconds time, const double quantum) const
{
return link::toPhaseEncodedBeats(mTimeline, time, link::Beats{quantum}).floating();
return link::toPhaseEncodedBeats(mState.timeline, time, link::Beats{quantum})
.floating();
}

template <typename Clock>
inline double BasicLink<Clock>::Timeline::phaseAtTime(
inline double Link::SessionState::phaseAtTime(
const std::chrono::microseconds time, const double quantum) const
{
return link::phase(link::Beats{beatAtTime(time, quantum)}, link::Beats{quantum})
.floating();
}

template <typename Clock>
inline std::chrono::microseconds BasicLink<Clock>::Timeline::timeAtBeat(
inline std::chrono::microseconds Link::SessionState::timeAtBeat(
const double beat, const double quantum) const
{
return link::fromPhaseEncodedBeats(mTimeline, link::Beats{beat}, link::Beats{quantum});
return link::fromPhaseEncodedBeats(
mState.timeline, link::Beats{beat}, link::Beats{quantum});
}

template <typename Clock>
inline void BasicLink<Clock>::Timeline::requestBeatAtTime(
inline void Link::SessionState::requestBeatAtTime(
const double beat, std::chrono::microseconds time, const double quantum)
{
if (mbRespectQuantum)
@@ -177,8 +206,7 @@ inline void BasicLink<Clock>::Timeline::requestBeatAtTime(
forceBeatAtTime(beat, time, quantum);
}

template <typename Clock>
inline void BasicLink<Clock>::Timeline::forceBeatAtTime(
inline void Link::SessionState::forceBeatAtTime(
const double beat, const std::chrono::microseconds time, const double quantum)
{
// There are two components to the beat adjustment: a phase shift
@@ -186,9 +214,42 @@ inline void BasicLink<Clock>::Timeline::forceBeatAtTime(
const auto curBeatAtTime = link::Beats{beatAtTime(time, quantum)};
const auto closestInPhase =
link::closestPhaseMatch(curBeatAtTime, link::Beats{beat}, link::Beats{quantum});
mTimeline = shiftClientTimeline(mTimeline, closestInPhase - curBeatAtTime);
mState.timeline = shiftClientTimeline(mState.timeline, closestInPhase - curBeatAtTime);
// Now adjust the magnitude
mTimeline.beatOrigin = mTimeline.beatOrigin + (link::Beats{beat} - closestInPhase);
mState.timeline.beatOrigin =
mState.timeline.beatOrigin + (link::Beats{beat} - closestInPhase);
}

inline void Link::SessionState::setIsPlaying(
const bool isPlaying, const std::chrono::microseconds time)
{
mState.startStopState = {isPlaying, time};
}

inline bool Link::SessionState::isPlaying() const
{
return mState.startStopState.isPlaying;
}

inline std::chrono::microseconds Link::SessionState::timeForIsPlaying() const
{
return mState.startStopState.time;
}

inline void Link::SessionState::requestBeatAtStartPlayingTime(
const double beat, const double quantum)
{
if (isPlaying())
{
requestBeatAtTime(beat, mState.startStopState.time, quantum);
}
}

inline void Link::SessionState::setIsPlayingAndRequestBeatAtTime(
bool isPlaying, std::chrono::microseconds time, double beat, double quantum)
{
mState.startStopState = {isPlaying, time};
requestBeatAtStartPlayingTime(beat, quantum);
}

} // ableton
} // namespace ableton

+ 2
- 2
source/modules/hylia/link/ableton/discovery/IpV4Interface.hpp View File

@@ -19,7 +19,7 @@

#pragma once

#include <ableton/platforms/asio/AsioService.hpp>
#include <ableton/platforms/asio/AsioWrapper.hpp>
#include <ableton/util/Injected.hpp>

namespace ableton
@@ -29,7 +29,7 @@ namespace discovery

inline asio::ip::udp::endpoint multicastEndpoint()
{
return {asio::ip::address::from_string("224.76.78.75"), 20808};
return {asio::ip::address_v4::from_string("224.76.78.75"), 20808};
}

// Type tags for dispatching between unicast and multicast packets


+ 80
- 30
source/modules/hylia/link/ableton/discovery/NetworkByteStreamSerializable.hpp View File

@@ -20,9 +20,9 @@
#pragma once

#include <ableton/platforms/asio/AsioWrapper.hpp>
#if LINK_PLATFORM_MACOSX
#if defined(LINK_PLATFORM_MACOSX)
#include <ableton/platforms/darwin/Darwin.hpp>
#elif LINK_PLATFORM_LINUX
#elif defined(LINK_PLATFORM_LINUX)
#include <ableton/platforms/linux/Linux.hpp>
#endif

@@ -32,10 +32,10 @@
#include <utility>
#include <vector>

#if LINK_PLATFORM_WINDOWS
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <Windows.h>
#if defined(LINK_PLATFORM_WINDOWS)
#include <ws2tcpip.h>
#include <winsock2.h>
#include <windows.h>
#endif

namespace ableton
@@ -80,7 +80,8 @@ struct Deserialize

// Default size implementation. Works for primitive types.

template <typename T>
template <typename T,
typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr>
std::uint32_t sizeInByteStream(T)
{
return sizeof(T);
@@ -235,29 +236,53 @@ struct Deserialize<int64_t>
}
};

// overloads for std::chrono durations
template <typename Rep, typename Ratio>
std::uint32_t sizeInByteStream(const std::chrono::duration<Rep, Ratio> dur)
// bool
inline std::uint32_t sizeInByteStream(bool)
{
return sizeof(uint8_t);
}

template <typename It>
It toNetworkByteStream(bool bl, It out)
{
return toNetworkByteStream(static_cast<uint8_t>(bl), std::move(out));
}

template <>
struct Deserialize<bool>
{
template <typename It>
static std::pair<bool, It> fromNetworkByteStream(It begin, It end)
{
auto result =
Deserialize<uint8_t>::fromNetworkByteStream(std::move(begin), std::move(end));
return std::make_pair(result.first != 0, result.second);
}
};

// std::chrono::microseconds
inline std::uint32_t sizeInByteStream(const std::chrono::microseconds micros)
{
return sizeInByteStream(dur.count());
return sizeInByteStream(micros.count());
}

template <typename Rep, typename Ratio, typename It>
It toNetworkByteStream(const std::chrono::duration<Rep, Ratio> dur, It out)
template <typename It>
It toNetworkByteStream(const std::chrono::microseconds micros, It out)
{
return toNetworkByteStream(dur.count(), std::move(out));
static_assert(sizeof(int64_t) == sizeof(std::chrono::microseconds::rep),
"The size of microseconds::rep must matche the size of int64_t.");
return toNetworkByteStream(static_cast<int64_t>(micros.count()), std::move(out));
}

template <typename Rep, typename Ratio>
struct Deserialize<std::chrono::duration<Rep, Ratio>>
template <>
struct Deserialize<std::chrono::microseconds>
{
template <typename It>
static std::pair<std::chrono::duration<Rep, Ratio>, It> fromNetworkByteStream(
It begin, It end)
static std::pair<std::chrono::microseconds, It> fromNetworkByteStream(It begin, It end)
{
using namespace std;
auto result = Deserialize<Rep>::fromNetworkByteStream(move(begin), move(end));
return make_pair(std::chrono::duration<Rep, Ratio>{result.first}, result.second);
auto result = Deserialize<int64_t>::fromNetworkByteStream(move(begin), move(end));
return make_pair(chrono::microseconds{result.first}, result.second);
}
};

@@ -305,7 +330,7 @@ BytesIt deserializeContainer(BytesIt bytesBegin,
return bytesBegin;
}

} // detail
} // namespace detail

// Need specific overloads for each container type, but use above
// utilities for common implementation
@@ -341,12 +366,13 @@ struct Deserialize<std::array<T, Size>>
template <typename T, typename Alloc>
std::uint32_t sizeInByteStream(const std::vector<T, Alloc>& vec)
{
return detail::containerSizeInByteStream(vec);
return sizeof(uint32_t) + detail::containerSizeInByteStream(vec);
}

template <typename T, typename Alloc, typename It>
It toNetworkByteStream(const std::vector<T, Alloc>& vec, It out)
{
out = toNetworkByteStream(static_cast<uint32_t>(vec.size()), out);
return detail::containerToNetworkByteStream(vec, std::move(out));
}

@@ -358,17 +384,42 @@ struct Deserialize<std::vector<T, Alloc>>
It bytesBegin, It bytesEnd)
{
using namespace std;
auto result_size =
Deserialize<uint32_t>::fromNetworkByteStream(move(bytesBegin), bytesEnd);
vector<T, Alloc> result;
// Use the number of bytes remaining in the stream as the upper
// bound on the number of elements that could be deserialized
// since we don't have a better heuristic.
auto resultIt = detail::deserializeContainer<T>(move(bytesBegin), move(bytesEnd),
back_inserter(result), static_cast<uint32_t>(distance(bytesBegin, bytesEnd)));

auto resultIt = detail::deserializeContainer<T>(
move(result_size.second), move(bytesEnd), back_inserter(result), result_size.first);
return make_pair(move(result), move(resultIt));
}
};

// 2-tuple
template <typename X, typename Y>
std::uint32_t sizeInByteStream(const std::tuple<X, Y>& tup)
{
return sizeInByteStream(std::get<0>(tup)) + sizeInByteStream(std::get<1>(tup));
}

template <typename X, typename Y, typename It>
It toNetworkByteStream(const std::tuple<X, Y>& tup, It out)
{
return toNetworkByteStream(
std::get<1>(tup), toNetworkByteStream(std::get<0>(tup), std::move(out)));
}

template <typename X, typename Y>
struct Deserialize<std::tuple<X, Y>>
{
template <typename It>
static std::pair<std::tuple<X, Y>, It> fromNetworkByteStream(It begin, It end)
{
using namespace std;
auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);
auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);
return make_pair(make_tuple(move(xres.first), move(yres.first)), move(yres.second));
}
};

// 3-tuple
template <typename X, typename Y, typename Z>
std::uint32_t sizeInByteStream(const std::tuple<X, Y, Z>& tup)
@@ -395,8 +446,7 @@ struct Deserialize<std::tuple<X, Y, Z>>
auto xres = Deserialize<X>::fromNetworkByteStream(begin, end);
auto yres = Deserialize<Y>::fromNetworkByteStream(xres.second, end);
auto zres = Deserialize<Z>::fromNetworkByteStream(yres.second, end);
return make_pair(
std::tuple<X, Y, Z>{move(xres.first), move(yres.first), move(zres.first)},
return make_pair(make_tuple(move(xres.first), move(yres.first), move(zres.first)),
move(zres.second));
}
};


+ 1
- 0
source/modules/hylia/link/ableton/discovery/Payload.hpp View File

@@ -21,6 +21,7 @@

#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
#include <functional>
#include <sstream>
#include <unordered_map>

namespace ableton


+ 4
- 6
source/modules/hylia/link/ableton/discovery/PeerGateway.hpp View File

@@ -21,7 +21,6 @@

#include <ableton/discovery/UdpMessenger.hpp>
#include <ableton/discovery/v1/Messages.hpp>
#include <ableton/platforms/asio/AsioService.hpp>
#include <ableton/util/SafeAsyncHandler.hpp>
#include <memory>

@@ -216,11 +215,10 @@ PeerGateway<Messenger, PeerObserver, IoContext> makePeerGateway(

// IpV4 gateway types
template <typename StateQuery, typename IoContext>
using IpV4Messenger =
UdpMessenger<IpV4Interface<typename util::Injected<IoContext>::type&,
v1::kMaxMessageSize>,
StateQuery,
IoContext>;
using IpV4Messenger = UdpMessenger<
IpV4Interface<typename util::Injected<IoContext>::type&, v1::kMaxMessageSize>,
StateQuery,
IoContext>;

template <typename PeerObserver, typename StateQuery, typename IoContext>
using IpV4Gateway =


+ 0
- 139
source/modules/hylia/link/ableton/discovery/Socket.hpp View File

@@ -1,139 +0,0 @@
/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <ableton/platforms/asio/AsioService.hpp>
#include <ableton/platforms/asio/AsioWrapper.hpp>
#include <ableton/util/SafeAsyncHandler.hpp>
#include <array>
#include <cassert>

namespace ableton
{
namespace discovery
{

template <std::size_t MaxPacketSize>
struct Socket
{
Socket(platforms::asio::AsioService& io)
: mpImpl(std::make_shared<Impl>(io))
{
}

Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;

Socket(Socket&& rhs)
: mpImpl(std::move(rhs.mpImpl))
{
}

std::size_t send(
const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)
{
assert(numBytes < MaxPacketSize);
return mpImpl->mSocket.send_to(asio::buffer(pData, numBytes), to);
}

template <typename Handler>
void receive(Handler handler)
{
mpImpl->mHandler = std::move(handler);
mpImpl->mSocket.async_receive_from(
asio::buffer(mpImpl->mReceiveBuffer, MaxPacketSize), mpImpl->mSenderEndpoint,
util::makeAsyncSafe(mpImpl));
}

asio::ip::udp::endpoint endpoint() const
{
return mpImpl->mSocket.local_endpoint();
}

struct Impl
{
Impl(platforms::asio::AsioService& io)
: mSocket(io.mService, asio::ip::udp::v4())
{
}

~Impl()
{
// Ignore error codes in shutdown and close as the socket may
// have already been forcibly closed
asio::error_code ec;
mSocket.shutdown(asio::ip::udp::socket::shutdown_both, ec);
mSocket.close(ec);
}

void operator()(const asio::error_code& error, const std::size_t numBytes)
{
if (!error && numBytes > 0 && numBytes <= MaxPacketSize)
{
const auto bufBegin = begin(mReceiveBuffer);
mHandler(mSenderEndpoint, bufBegin, bufBegin + static_cast<ptrdiff_t>(numBytes));
}
}

asio::ip::udp::socket mSocket;
asio::ip::udp::endpoint mSenderEndpoint;
using Buffer = std::array<uint8_t, MaxPacketSize>;
Buffer mReceiveBuffer;
using ByteIt = typename Buffer::const_iterator;
std::function<void(const asio::ip::udp::endpoint&, ByteIt, ByteIt)> mHandler;
};

std::shared_ptr<Impl> mpImpl;
};

// Configure an asio socket for receiving multicast messages
template <std::size_t MaxPacketSize>
void configureMulticastSocket(Socket<MaxPacketSize>& socket,
const asio::ip::address_v4& addr,
const asio::ip::udp::endpoint& multicastEndpoint)
{
socket.mpImpl->mSocket.set_option(asio::ip::udp::socket::reuse_address(true));
// ???
socket.mpImpl->mSocket.set_option(asio::socket_base::broadcast(!addr.is_loopback()));
// ???
socket.mpImpl->mSocket.set_option(
asio::ip::multicast::enable_loopback(addr.is_loopback()));
socket.mpImpl->mSocket.set_option(asio::ip::multicast::outbound_interface(addr));
// Is from_string("0.0.0.0") best approach?
socket.mpImpl->mSocket.bind(
{asio::ip::address::from_string("0.0.0.0"), multicastEndpoint.port()});
socket.mpImpl->mSocket.set_option(
asio::ip::multicast::join_group(multicastEndpoint.address().to_v4(), addr));
}

// Configure an asio socket for receiving unicast messages
template <std::size_t MaxPacketSize>
void configureUnicastSocket(
Socket<MaxPacketSize>& socket, const asio::ip::address_v4& addr)
{
// ??? really necessary?
socket.mpImpl->mSocket.set_option(
asio::ip::multicast::enable_loopback(addr.is_loopback()));
socket.mpImpl->mSocket.set_option(asio::ip::multicast::outbound_interface(addr));
socket.mpImpl->mSocket.bind(asio::ip::udp::endpoint{addr, 0});
}

} // namespace discovery
} // namespace ableton

+ 1
- 1
source/modules/hylia/link/ableton/discovery/UdpMessenger.hpp View File

@@ -169,7 +169,7 @@ private:
void setReceiveHandler(Handler handler)
{
mPeerStateHandler = [handler](
PeerState<NodeState> state) { handler(std::move(state)); };
PeerState<NodeState> state) { handler(std::move(state)); };

mByeByeHandler = [handler](ByeBye<NodeId> byeBye) { handler(std::move(byeBye)); };
}


+ 2
- 2
source/modules/hylia/link/ableton/discovery/test/Interface.hpp View File

@@ -42,8 +42,8 @@ public:
template <typename Callback, typename Tag>
void receive(Callback callback, Tag tag)
{
mCallback = [callback, tag](
const asio::ip::udp::endpoint& from, const std::vector<uint8_t>& buffer) {
mCallback = [callback, tag](const asio::ip::udp::endpoint& from,
const std::vector<uint8_t>& buffer) {
callback(tag, from, begin(buffer), end(buffer));
};
}


+ 43
- 8
source/modules/hylia/link/ableton/discovery/test/PayloadEntries.hpp View File

@@ -21,6 +21,7 @@

#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
#include <cstdint>
#include <tuple>
#include <utility>

namespace ableton
@@ -35,10 +36,8 @@ namespace test
// A fixed-size entry type
struct Foo
{
enum
{
key = '_foo'
};
static const std::int32_t key = '_foo';
static_assert(key == 0x5f666f6f, "Unexpected byte order");

std::int32_t fooVal;

@@ -66,10 +65,8 @@ struct Foo
// A variable-size entry type
struct Bar
{
enum
{
key = '_bar'
};
static const std::int32_t key = '_bar';
static_assert(key == 0x5f626172, "Unexpected byte order");

std::vector<std::uint64_t> barVals;

@@ -93,6 +90,44 @@ struct Bar
}
};

// An entry type with two vectors
struct Foobar
{
static const std::int32_t key = 'fbar';
static_assert(key == 0x66626172, "Unexpected byte order");

using FoobarVector = std::vector<std::uint64_t>;
using FoobarTuple = std::tuple<FoobarVector, FoobarVector>;

FoobarVector fooVals;
FoobarVector barVals;

friend std::uint32_t sizeInByteStream(const Foobar& foobar)
{
return discovery::sizeInByteStream(foobar.asTuple());
}

template <typename It>
friend It toNetworkByteStream(const Foobar& foobar, It out)
{
return discovery::toNetworkByteStream(foobar.asTuple(), out);
}

template <typename It>
static std::pair<Foobar, It> fromNetworkByteStream(It begin, It end)
{
const auto result =
Deserialize<FoobarTuple>::fromNetworkByteStream(std::move(begin), std::move(end));
const auto foobar = Foobar{std::get<0>(result.first), std::get<1>(result.first)};
return std::make_pair(std::move(foobar), std::move(result.second));
}

FoobarTuple asTuple() const
{
return std::make_tuple(fooVals, barVals);
}
};

} // namespace test
} // namespace discovery
} // namespace ableton

+ 3
- 1
source/modules/hylia/link/ableton/discovery/test/Socket.hpp View File

@@ -53,7 +53,9 @@ public:
void receive(Handler handler)
{
mCallback = [handler](const asio::ip::udp::endpoint& from,
const std::vector<uint8_t>& buffer) { handler(from, begin(buffer), end(buffer)); };
const std::vector<uint8_t>& buffer) {
handler(from, begin(buffer), end(buffer));
};
}

template <typename It>


+ 6
- 26
source/modules/hylia/link/ableton/link/CircularFifo.hpp View File

@@ -19,6 +19,7 @@

#pragma once

#include <ableton/link/Optional.hpp>
#include <array>
#include <atomic>
#include <cassert>
@@ -34,12 +35,6 @@ template <typename Type, std::size_t size>
class CircularFifo
{
public:
struct PoppedItem
{
Type item;
bool valid;
};

CircularFifo()
: tail(0)
, head(0)
@@ -60,32 +55,17 @@ public:
return false;
}

PoppedItem pop()
Optional<Type> pop()
{
const auto currentHead = head.load();
if (currentHead == tail.load())
{
return {Type{}, false};
return {};
}

auto item = data[currentHead];
head.store(nextIndex(currentHead));
return {std::move(item), true};
}

PoppedItem clearAndPopLast()
{
auto hasData = false;
auto currentHead = head.load();
while (currentHead != tail.load())
{
currentHead = nextIndex(currentHead);
hasData = true;
}

auto item = data[previousIndex(currentHead)];
head.store(currentHead);
return {std::move(item), hasData};
return Optional<Type>{std::move(item)};
}

bool isEmpty() const
@@ -109,5 +89,5 @@ private:
std::array<Type, size + 1> data;
};

} // link
} // ableton
} // namespace link
} // namespace ableton

+ 2
- 2
source/modules/hylia/link/ableton/link/ClientSessionTimelines.hpp View File

@@ -111,5 +111,5 @@ inline Timeline shiftClientTimeline(Timeline client, const Beats shift)
return client;
}

} // link
} // ableton
} // namespace link
} // namespace ableton

+ 376
- 115
source/modules/hylia/link/ableton/link/Controller.hpp View File

@@ -26,7 +26,9 @@
#include <ableton/link/GhostXForm.hpp>
#include <ableton/link/NodeState.hpp>
#include <ableton/link/Peers.hpp>
#include <ableton/link/SessionState.hpp>
#include <ableton/link/Sessions.hpp>
#include <ableton/link/StartStopState.hpp>
#include <mutex>

namespace ableton
@@ -44,20 +46,79 @@ GhostXForm initXForm(const Clock& clock)
return {1.0, -clock.micros()};
}

template <typename Clock>
inline SessionState initSessionState(const Tempo tempo, const Clock& clock)
{
using namespace std::chrono;
return {clampTempo(Timeline{tempo, Beats{0.}, microseconds{0}}),
StartStopState{false, Beats{0.}, microseconds{0}}, initXForm(clock)};
}

inline ClientState initClientState(const SessionState& sessionState)
{
const auto hostTime = sessionState.ghostXForm.ghostToHost(std::chrono::microseconds{0});
return {
Timeline{sessionState.timeline.tempo, sessionState.timeline.beatOrigin, hostTime},
StartStopState{sessionState.startStopState.isPlaying,
sessionState.startStopState.beats, hostTime}};
}

inline RtClientState initRtClientState(const ClientState& clientState)
{
using namespace std::chrono;
return {
clientState.timeline, clientState.startStopState, microseconds{0}, microseconds{0}};
}

// The timespan in which local modifications to the timeline will be
// preferred over any modifications coming from the network.
const auto kLocalModGracePeriod = std::chrono::milliseconds(1000);
const auto kRtHandlerFallbackPeriod = kLocalModGracePeriod / 2;

inline StartStopState selectPreferredStartStopState(
const StartStopState currentStartStopState, const StartStopState startStopState)
{
return startStopState.timestamp > currentStartStopState.timestamp
? startStopState
: currentStartStopState;
}

inline StartStopState mapStartStopStateFromSessionToClient(
const StartStopState& sessionStartStopState,
const Timeline& clientTimeline,
const Timeline& sessionTimeline,
const GhostXForm& xForm)
{
const auto clientBeats = clientTimeline.toBeats(
xForm.ghostToHost(sessionTimeline.fromBeats(sessionStartStopState.beats)));
const auto clientTime = xForm.ghostToHost(sessionStartStopState.timestamp);
return StartStopState{sessionStartStopState.isPlaying, clientBeats, clientTime};
}

inline StartStopState mapStartStopStateFromClientToSession(
const StartStopState& clientStartStopState,
const Timeline& clientTimeline,
const Timeline& sessionTimeline,
const GhostXForm& xForm)
{
const auto sessionBeats = sessionTimeline.toBeats(
xForm.hostToGhost(clientTimeline.fromBeats(clientStartStopState.beats)));
const auto sessionTime = xForm.hostToGhost(clientStartStopState.timestamp);
return StartStopState{clientStartStopState.isPlaying, sessionBeats, sessionTime};
}

} // namespace detail

// function types corresponding to the Controller callback type params
using PeerCountCallback = std::function<void(std::size_t)>;
using TempoCallback = std::function<void(ableton::link::Tempo)>;
using StartStopStateCallback = std::function<void(bool)>;


// The main Link controller
template <typename PeerCountCallback,
typename TempoCallback,
typename StartStopStateCallback,
typename Clock,
typename IoContext>
class Controller
@@ -66,33 +127,38 @@ public:
Controller(Tempo tempo,
PeerCountCallback peerCallback,
TempoCallback tempoCallback,
StartStopStateCallback startStopStateCallback,
Clock clock,
util::Injected<IoContext> io)
: mTempoCallback(std::move(tempoCallback))
, mStartStopStateCallback(std::move(startStopStateCallback))
, mClock(std::move(clock))
, mNodeId(NodeId::random())
, mSessionId(mNodeId)
, mGhostXForm(detail::initXForm(mClock))
, mSessionTimeline(clampTempo({tempo, Beats{0.}, std::chrono::microseconds{0}}))
, mClientTimeline({mSessionTimeline.tempo, Beats{0.},
mGhostXForm.ghostToHost(std::chrono::microseconds{0})})
, mRtClientTimeline(mClientTimeline)
, mRtClientTimelineTimestamp(0)
, mSessionState(detail::initSessionState(tempo, mClock))
, mClientState(detail::initClientState(mSessionState))
, mLastIsPlayingForStartStopStateCallback(false)
, mRtClientState(detail::initRtClientState(mClientState))
, mHasPendingRtClientStates(false)
, mSessionPeerCounter(*this, std::move(peerCallback))
, mEnabled(false)
, mStartStopSyncEnabled(false)
, mIo(std::move(io))
, mRtTimelineSetter(*this)
, mRtClientStateSetter(*this)
, mPeers(util::injectRef(*mIo),
std::ref(mSessionPeerCounter),
SessionTimelineCallback{*this})
, mSessions({mSessionId, mSessionTimeline, {mGhostXForm, mClock.micros()}},
SessionTimelineCallback{*this},
SessionStartStopStateCallback{*this})
, mSessions(
{mSessionId, mSessionState.timeline, {mSessionState.ghostXForm, mClock.micros()}},
util::injectRef(mPeers),
MeasurePeer{*this},
JoinSessionCallback{*this},
util::injectRef(*mIo),
mClock)
, mDiscovery(
std::make_pair(NodeState{mNodeId, mSessionId, mSessionTimeline}, mGhostXForm),
, mDiscovery(std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,
mSessionState.startStopState},
mSessionState.ghostXForm),
GatewayFactory{*this},
util::injectVal(mIo->clone(UdpSendExceptionHandler{*this})))
{
@@ -126,102 +192,186 @@ public:
return mEnabled;
}

void enableStartStopSync(const bool bEnable)
{
mStartStopSyncEnabled = bEnable;
}

bool isStartStopSyncEnabled() const
{
return mStartStopSyncEnabled;
}

std::size_t numPeers() const
{
return mSessionPeerCounter.mSessionPeerCount;
}

// Get the current Link timeline. Thread-safe but may block, so
// Get the current Link client state. Thread-safe but may block, so
// it cannot be used from audio thread.
Timeline timeline() const
ClientState clientState() const
{
std::lock_guard<std::mutex> lock(mClientTimelineGuard);
return mClientTimeline;
std::lock_guard<std::mutex> lock(mClientStateGuard);
return mClientState;
}

// Set the timeline to be used, starting at the given
// time. Thread-safe but may block, so it cannot be used from audio thread.
void setTimeline(Timeline newTimeline, const std::chrono::microseconds atTime)
// Set the client state to be used, starting at the given time.
// Thread-safe but may block, so it cannot be used from audio thread.
void setClientState(IncomingClientState newClientState)
{
newTimeline = clampTempo(newTimeline);
{
std::lock_guard<std::mutex> lock(mClientTimelineGuard);
mClientTimeline = newTimeline;
std::lock_guard<std::mutex> lock(mClientStateGuard);
if (newClientState.timeline)
{
*newClientState.timeline = clampTempo(*newClientState.timeline);
mClientState.timeline = *newClientState.timeline;
}
if (newClientState.startStopState)
{
// Prevent updating client start stop state with an outdated start stop state
*newClientState.startStopState = detail::selectPreferredStartStopState(
mClientState.startStopState, *newClientState.startStopState);
mClientState.startStopState = *newClientState.startStopState;
}
}
mIo->async([this, newTimeline, atTime] {
handleTimelineFromClient(updateSessionTimelineFromClient(
mSessionTimeline, newTimeline, atTime, mGhostXForm));
});

mIo->async([this, newClientState] { handleClientState(newClientState); });
}

// Non-blocking timeline access for a realtime context. NOT
// Non-blocking client state access for a realtime context. NOT
// thread-safe. Must not be called from multiple threads
// concurrently and must not be called concurrently with setTimelineRtSafe.
Timeline timelineRtSafe() const
// concurrently and must not be called concurrently with setClientStateRtSafe.
ClientState clientStateRtSafe() const
{
// Respect the session timing guard but don't block on it. If we
// can't access it because it's being modified we fall back to our
// cached version of the timeline.
const auto now = mClock.micros();
if (now - mRtClientTimelineTimestamp > detail::kLocalModGracePeriod
&& !mRtTimelineSetter.hasPendingTimelines() && mSessionTimingGuard.try_lock())
// Respect the session state guard and the client state guard but don't
// block on them. If we can't access one or both because of concurrent modification
// we fall back to our cached version of the timeline and/or start stop state.

if (!mHasPendingRtClientStates)
{
const auto clientTimeline = updateClientTimelineFromSession(
mRtClientTimeline, mSessionTimeline, now, mGhostXForm);
const auto now = mClock.micros();
const auto timelineGracePeriodOver =
now - mRtClientState.timelineTimestamp > detail::kLocalModGracePeriod;
const auto startStopStateGracePeriodOver =
now - mRtClientState.startStopStateTimestamp > detail::kLocalModGracePeriod;

if ((timelineGracePeriodOver || startStopStateGracePeriodOver)
&& mClientStateGuard.try_lock())
{
const auto clientState = mClientState;
mClientStateGuard.unlock();

mSessionTimingGuard.unlock();
if (timelineGracePeriodOver && clientState.timeline != mRtClientState.timeline)
{
mRtClientState.timeline = clientState.timeline;
}

if (clientTimeline != mRtClientTimeline)
{
mRtClientTimeline = clientTimeline;
if (startStopStateGracePeriodOver
&& clientState.startStopState != mRtClientState.startStopState)
{
mRtClientState.startStopState = clientState.startStopState;
}
}
}

return mRtClientTimeline;
return {mRtClientState.timeline, mRtClientState.startStopState};
}

// should only be called from the audio thread
void setTimelineRtSafe(Timeline newTimeline, const std::chrono::microseconds atTime)
void setClientStateRtSafe(IncomingClientState newClientState)
{
newTimeline = clampTempo(newTimeline);
if (!newClientState.timeline && !newClientState.startStopState)
{
return;
}

// This will fail in case the Fifo in the RtTimelineSetter is full. This indicates a
// very high rate of calls to the setter. In this case we ignore one value because we
// expect the setter to be called again soon.
if (mRtTimelineSetter.tryPush(newTimeline, atTime))
if (newClientState.timeline)
{
// Cache the new timeline for serving back to the client
mRtClientTimeline = newTimeline;
mRtClientTimelineTimestamp =
isEnabled() ? mClock.micros() : std::chrono::microseconds(0);
*newClientState.timeline = clampTempo(*newClientState.timeline);
}

if (newClientState.startStopState)
{
// Prevent updating client start stop state with an outdated start stop state
*newClientState.startStopState = detail::selectPreferredStartStopState(
mRtClientState.startStopState, *newClientState.startStopState);
}

// This flag ensures that mRtClientState is only updated after all incoming
// client states were processed
mHasPendingRtClientStates = true;
// This will fail in case the Fifo in the RtClientStateSetter is full. This indicates
// a very high rate of calls to the setter. In this case we ignore one value because
// we expect the setter to be called again soon.
if (mRtClientStateSetter.tryPush(newClientState))
{
const auto now = mClock.micros();
// Cache the new timeline and StartStopState for serving back to the client
if (newClientState.timeline)
{
// Cache the new timeline and StartStopState for serving back to the client
mRtClientState.timeline = *newClientState.timeline;
mRtClientState.timelineTimestamp = makeRtTimestamp(now);
}
if (newClientState.startStopState)
{
mRtClientState.startStopState = *newClientState.startStopState;
mRtClientState.startStopStateTimestamp = makeRtTimestamp(now);
}
}
}

private:
std::chrono::microseconds makeRtTimestamp(const std::chrono::microseconds now) const
{
return isEnabled() ? now : std::chrono::microseconds(0);
}

void invokeStartStopStateCallbackIfChanged()
{
bool shouldInvokeCallback = false;
{
std::lock_guard<std::mutex> lock(mClientStateGuard);
shouldInvokeCallback =
mLastIsPlayingForStartStopStateCallback != mClientState.startStopState.isPlaying;
mLastIsPlayingForStartStopStateCallback = mClientState.startStopState.isPlaying;
}

if (shouldInvokeCallback)
{
mStartStopStateCallback(mLastIsPlayingForStartStopStateCallback);
}
}

void updateDiscovery()
{
// Push the change to the discovery service
mDiscovery.updateNodeState(
std::make_pair(NodeState{mNodeId, mSessionId, mSessionState.timeline,
mSessionState.startStopState},
mSessionState.ghostXForm));
}

void updateSessionTiming(const Timeline newTimeline, const GhostXForm newXForm)
{
const auto oldTimeline = mSessionTimeline;
const auto oldXForm = mGhostXForm;
const auto oldTimeline = mSessionState.timeline;
const auto oldXForm = mSessionState.ghostXForm;

if (oldTimeline != newTimeline || oldXForm != newXForm)
{
{
std::lock_guard<std::mutex> lock(mSessionTimingGuard);
mSessionTimeline = newTimeline;
mGhostXForm = newXForm;
std::lock_guard<std::mutex> lock(mSessionStateGuard);
mSessionState.timeline = newTimeline;
mSessionState.ghostXForm = newXForm;
}

// Update the client timeline based on the new session timing data
{
std::lock_guard<std::mutex> lock(mClientTimelineGuard);
mClientTimeline = updateClientTimelineFromSession(
mClientTimeline, mSessionTimeline, mClock.micros(), mGhostXForm);
std::lock_guard<std::mutex> lock(mClientStateGuard);
mClientState.timeline = updateClientTimelineFromSession(mClientState.timeline,
mSessionState.timeline, mClock.micros(), mSessionState.ghostXForm);
}

// Push the change to the discovery service
mDiscovery.updateNodeState(
std::make_pair(NodeState{mNodeId, mSessionId, newTimeline}, newXForm));

if (oldTimeline.tempo != newTimeline.tempo)
{
mTempoCallback(newTimeline.tempo);
@@ -229,36 +379,126 @@ private:
}
}

void handleTimelineFromClient(Timeline tl)
{
mSessions.resetTimeline(tl);
mPeers.setSessionTimeline(mSessionId, tl);
updateSessionTiming(std::move(tl), mGhostXForm);
}

void handleTimelineFromSession(SessionId id, Timeline timeline)
{
debug(mIo->log()) << "Received timeline with tempo: " << timeline.tempo.bpm()
<< " for session: " << id;
updateSessionTiming(
mSessions.sawSessionTimeline(std::move(id), std::move(timeline)), mGhostXForm);
updateSessionTiming(mSessions.sawSessionTimeline(std::move(id), std::move(timeline)),
mSessionState.ghostXForm);
updateDiscovery();
}

void resetSessionStartStopState()
{
mSessionState.startStopState = StartStopState{};
}

void handleStartStopStateFromSession(SessionId sessionId, StartStopState startStopState)
{
debug(mIo->log()) << "Received start stop state. isPlaying: "
<< startStopState.isPlaying
<< ", beats: " << startStopState.beats.floating()
<< ", time: " << startStopState.timestamp.count()
<< " for session: " << sessionId;
if (sessionId == mSessionId
&& startStopState.timestamp > mSessionState.startStopState.timestamp)
{
mSessionState.startStopState = startStopState;

// Always propagate the session start stop state so even a client that doesn't have
// the feature enabled can function as a relay.
updateDiscovery();

if (mStartStopSyncEnabled)
{
{
std::lock_guard<std::mutex> lock(mClientStateGuard);
mClientState.startStopState =
detail::mapStartStopStateFromSessionToClient(startStopState,
mClientState.timeline, mSessionState.timeline, mSessionState.ghostXForm);
}
invokeStartStopStateCallbackIfChanged();
}
}
}

void handleClientState(const IncomingClientState clientState)
{
auto mustUpdateDiscovery = false;

if (clientState.timeline)
{
auto sessionTimeline = updateSessionTimelineFromClient(mSessionState.timeline,
*clientState.timeline, clientState.timelineTimestamp, mSessionState.ghostXForm);

mSessions.resetTimeline(sessionTimeline);
mPeers.setSessionTimeline(mSessionId, sessionTimeline);
updateSessionTiming(std::move(sessionTimeline), mSessionState.ghostXForm);

mustUpdateDiscovery = true;
}

if (mStartStopSyncEnabled && clientState.startStopState)
{
// Prevent updating with an outdated start stop state
const auto newGhostTime =
mSessionState.ghostXForm.hostToGhost(clientState.startStopState->timestamp);
if (newGhostTime > mSessionState.startStopState.timestamp)
{
{
std::lock_guard<std::mutex> lock(mClientStateGuard);
mSessionState.startStopState =
detail::mapStartStopStateFromClientToSession(*clientState.startStopState,
mClientState.timeline, mSessionState.timeline, mSessionState.ghostXForm);
mClientState.startStopState = *clientState.startStopState;
}

mustUpdateDiscovery = true;
}
}

if (mustUpdateDiscovery)
{
updateDiscovery();
}

invokeStartStopStateCallbackIfChanged();
}

void handleRtTimeline(const Timeline timeline, const std::chrono::microseconds time)
void handleRtClientState(IncomingClientState clientState)
{
{
std::lock_guard<std::mutex> lock(mClientTimelineGuard);
mClientTimeline = timeline;
std::lock_guard<std::mutex> lock(mClientStateGuard);
if (clientState.timeline)
{
mClientState.timeline = *clientState.timeline;
}
if (clientState.startStopState)
{
// Prevent updating client start stop state with an outdated start stop state
*clientState.startStopState = detail::selectPreferredStartStopState(
mClientState.startStopState, *clientState.startStopState);
mClientState.startStopState = *clientState.startStopState;
}
}
handleTimelineFromClient(
updateSessionTimelineFromClient(mSessionTimeline, timeline, time, mGhostXForm));

handleClientState(clientState);
mHasPendingRtClientStates = false;
}

void joinSession(const Session& session)
{
const bool sessionIdChanged = mSessionId != session.sessionId;
mSessionId = session.sessionId;

// Prevent passing the start stop state of the previous session to the new one.
if (sessionIdChanged)
{
resetSessionStartStopState();
}

updateSessionTiming(session.timeline, session.measurement.xform);
updateDiscovery();

if (sessionIdChanged)
{
@@ -279,11 +519,14 @@ private:
// the beat on the old session timeline corresponding to the
// current host time and mapping it to the new ghost time
// representation of the current host time.
const auto newTl = Timeline{mSessionTimeline.tempo,
mSessionTimeline.toBeats(mGhostXForm.hostToGhost(hostTime)),
const auto newTl = Timeline{mSessionState.timeline.tempo,
mSessionState.timeline.toBeats(mSessionState.ghostXForm.hostToGhost(hostTime)),
xform.hostToGhost(hostTime)};

resetSessionStartStopState();

updateSessionTiming(newTl, xform);
updateDiscovery();

mSessions.resetSession({mNodeId, newTl, {xform, hostTime}});
mPeers.resetPeers();
@@ -299,25 +542,22 @@ private:
Controller& mController;
};

struct RtTimelineSetter
struct RtClientStateSetter
{
using CallbackDispatcher =
typename IoContext::template LockFreeCallbackDispatcher<std::function<void()>,
std::chrono::milliseconds>;
using RtTimeline = std::pair<Timeline, std::chrono::microseconds>;

RtTimelineSetter(Controller& controller)
RtClientStateSetter(Controller& controller)
: mController(controller)
, mHasPendingTimelines(false)
, mCallbackDispatcher(
[this] { processPendingTimelines(); }, detail::kRtHandlerFallbackPeriod)
[this] { processPendingClientStates(); }, detail::kRtHandlerFallbackPeriod)
{
}

bool tryPush(const Timeline timeline, const std::chrono::microseconds time)
bool tryPush(const IncomingClientState clientState)
{
mHasPendingTimelines = true;
const auto success = mFifo.push({timeline, time});
const auto success = mClientStateFifo.push(clientState);
if (success)
{
mCallbackDispatcher.invoke();
@@ -325,34 +565,51 @@ private:
return success;
}

bool hasPendingTimelines() const
{
return mHasPendingTimelines;
}

private:
void processPendingTimelines()
IncomingClientState buildMergedPendingClientState()
{
auto result = mFifo.clearAndPopLast();

if (result.valid)
auto clientState = IncomingClientState{};
while (const auto result = mClientStateFifo.pop())
{
auto timeline = std::move(result.item);
mController.mIo->async([this, timeline]() {
mController.handleRtTimeline(timeline.first, timeline.second);
mHasPendingTimelines = false;
});
if (result->timeline)
{
clientState.timeline = result->timeline;
clientState.timelineTimestamp = result->timelineTimestamp;
}
if (result->startStopState)
{
clientState.startStopState = result->startStopState;
}
}
return clientState;
}

void processPendingClientStates()
{
const auto clientState = buildMergedPendingClientState();
mController.mIo->async(
[this, clientState]() { mController.handleRtClientState(clientState); });
}

Controller& mController;
// Assuming a wake up time of one ms for the threads owned by the CallbackDispatcher
// and the ioService, buffering 16 timelines allows to set eight timelines per ms.
CircularFifo<RtTimeline, 16> mFifo;
std::atomic<bool> mHasPendingTimelines;
// and the ioService, buffering 16 client states allows to set eight client states
// per ms.
static const std::size_t kBufferSize = 16;
CircularFifo<IncomingClientState, kBufferSize> mClientStateFifo;
CallbackDispatcher mCallbackDispatcher;
};

struct SessionStartStopStateCallback
{
void operator()(SessionId sessionId, StartStopState startStopState)
{
mController.handleStartStopStateFromSession(sessionId, startStopState);
}

Controller& mController;
};

struct SessionPeerCounter
{
SessionPeerCounter(Controller& controller, PeerCountCallback callback)
@@ -423,8 +680,10 @@ private:

using IoType = typename util::Injected<IoContext>::type;

using ControllerPeers =
Peers<IoType&, std::reference_wrapper<SessionPeerCounter>, SessionTimelineCallback>;
using ControllerPeers = Peers<IoType&,
std::reference_wrapper<SessionPeerCounter>,
SessionTimelineCallback,
SessionStartStopStateCallback>;

using ControllerGateway =
Gateway<typename ControllerPeers::GatewayObserver, Clock, IoType&>;
@@ -464,28 +723,30 @@ private:
};

TempoCallback mTempoCallback;
StartStopStateCallback mStartStopStateCallback;
Clock mClock;
NodeId mNodeId;
SessionId mSessionId;

// Mutex that controls access to mGhostXForm and mSessionTimeline
mutable std::mutex mSessionTimingGuard;
GhostXForm mGhostXForm;
Timeline mSessionTimeline;
mutable std::mutex mSessionStateGuard;
SessionState mSessionState;

mutable std::mutex mClientTimelineGuard;
Timeline mClientTimeline;
mutable std::mutex mClientStateGuard;
ClientState mClientState;
bool mLastIsPlayingForStartStopStateCallback;

mutable Timeline mRtClientTimeline;
std::chrono::microseconds mRtClientTimelineTimestamp;
mutable RtClientState mRtClientState;
std::atomic<bool> mHasPendingRtClientStates;

SessionPeerCounter mSessionPeerCounter;

std::atomic<bool> mEnabled;

std::atomic<bool> mStartStopSyncEnabled;

util::Injected<IoContext> mIo;

RtTimelineSetter mRtTimelineSetter;
RtClientStateSetter mRtClientStateSetter;

ControllerPeers mPeers;



+ 5
- 6
source/modules/hylia/link/ableton/link/Gateway.hpp View File

@@ -38,14 +38,13 @@ public:
NodeState nodeState,
GhostXForm ghostXForm,
Clock clock)
// TODO: Measurement should have an IoContext injected
: mIo(std::move(io)),
mMeasurement(addr,
: mIo(std::move(io))
, mMeasurement(addr,
nodeState.sessionId,
std::move(ghostXForm),
std::move(clock),
util::injectVal(channel(mIo->log(), "gateway@" + addr.to_string()))),
mPeerGateway(discovery::makeIpV4Gateway(util::injectRef(*mIo),
util::injectVal(mIo->clone()))
, mPeerGateway(discovery::makeIpV4Gateway(util::injectRef(*mIo),
std::move(addr),
std::move(observer),
PeerState{std::move(nodeState), mMeasurement.endpoint()}))
@@ -84,7 +83,7 @@ public:

private:
util::Injected<IoContext> mIo;
MeasurementService<Clock, typename util::Injected<IoContext>::type::Log> mMeasurement;
MeasurementService<Clock, typename std::remove_reference<IoContext>::type> mMeasurement;
discovery::
IpV4Gateway<PeerObserver, PeerState, typename util::Injected<IoContext>::type&>
mPeerGateway;


+ 36
- 63
source/modules/hylia/link/ableton/link/Measurement.hpp View File

@@ -20,13 +20,12 @@
#pragma once

#include <ableton/discovery/Payload.hpp>
#include <ableton/discovery/Socket.hpp>
#include <ableton/link/PayloadEntries.hpp>
#include <ableton/link/PeerState.hpp>
#include <ableton/link/SessionId.hpp>
#include <ableton/link/v1/Messages.hpp>
#include <ableton/platforms/asio/AsioService.hpp>
#include <ableton/util/Injected.hpp>
#include <ableton/util/SafeAsyncHandler.hpp>
#include <chrono>
#include <memory>

@@ -35,83 +34,57 @@ namespace ableton
namespace link
{

template <typename IoService, typename Clock, typename Socket, typename Log>
template <typename Clock, typename IoContext>
struct Measurement
{
using Point = std::pair<double, double>;
using Callback = std::function<void(std::vector<Point>)>;
using Micros = std::chrono::microseconds;
using Timer = typename IoService::Timer;

static const std::size_t kNumberDataPoints = 100;
static const std::size_t kNumberMeasurements = 5;

Measurement() = default;

Measurement(const PeerState& state,
Callback callback,
asio::ip::address_v4 address,
Clock clock,
util::Injected<Log> log)
: mpIo(new IoService{})
, mpImpl(std::make_shared<Impl>(*mpIo,
std::move(state),
IoContext io)
: mIo(std::move(io))
, mpImpl(std::make_shared<Impl>(std::move(state),
std::move(callback),
std::move(address),
std::move(clock),
std::move(log)))
mIo))
{
mpImpl->listen();
}

Measurement(Measurement&& rhs)
: mpIo(std::move(rhs.mpIo))
, mpImpl(std::move(rhs.mpImpl))
{
}

~Measurement()
{
postImplDestruction();
}

Measurement& operator=(Measurement&& rhs)
{
postImplDestruction();
mpIo = std::move(rhs.mpIo);
mpImpl = std::move(rhs.mpImpl);
return *this;
}

void postImplDestruction()
{
// Post destruction of the impl object into the io thread if valid
if (mpIo)
{
mpIo->post(ImplDeleter{*this});
}
}
Measurement(const Measurement&) = delete;
Measurement& operator=(Measurement&) = delete;
Measurement(const Measurement&&) = delete;
Measurement& operator=(Measurement&&) = delete;

struct Impl : std::enable_shared_from_this<Impl>
{
Impl(IoService& io,
const PeerState& state,
using Socket = typename IoContext::template Socket<v1::kMaxMessageSize>;
using Timer = typename IoContext::Timer;
using Log = typename IoContext::Log;

Impl(const PeerState& state,
Callback callback,
asio::ip::address_v4 address,
Clock clock,
util::Injected<Log> log)
: mpSocket(std::make_shared<Socket>(io))
IoContext& io)
: mSocket(io.template openUnicastSocket<v1::kMaxMessageSize>(address))
, mSessionId(state.nodeState.sessionId)
, mEndpoint(state.endpoint)
, mCallback(std::move(callback))
, mClock(std::move(clock))
, mTimer(util::injectVal(io.makeTimer()))
, mTimer(io.makeTimer())
, mMeasurementsStarted(0)
, mLog(std::move(log))
, mLog(channel(io.log(), "Measurement on gateway@" + address.to_string()))
, mSuccess(false)
{
configureUnicastSocket(*mpSocket, address);

const auto ht = HostTime{mClock.micros()};
sendPing(mEndpoint, discovery::makePayload(ht));
resetTimer();
@@ -119,9 +92,9 @@ struct Measurement

void resetTimer()
{
mTimer->cancel();
mTimer->expires_from_now(std::chrono::milliseconds(50));
mTimer->async_wait([this](const typename Timer::ErrorCode e) {
mTimer.cancel();
mTimer.expires_from_now(std::chrono::milliseconds(50));
mTimer.async_wait([this](const typename Timer::ErrorCode e) {
if (!e)
{
if (mMeasurementsStarted < kNumberMeasurements)
@@ -141,7 +114,7 @@ struct Measurement

void listen()
{
mpSocket->receive(util::makeAsyncSafe(this->shared_from_this()));
mSocket.receive(util::makeAsyncSafe(this->shared_from_this()));
}

// Operator to handle incoming messages on the interface
@@ -156,7 +129,7 @@ struct Measurement

if (header.messageType == v1::kPong)
{
debug(*mLog) << "Received Pong message from " << from;
debug(mLog) << "Received Pong message from " << from;

// parse for all entries
SessionId sessionId{};
@@ -175,7 +148,7 @@ struct Measurement
}
catch (const std::runtime_error& err)
{
warning(*mLog) << "Failed parsing payload, caught exception: " << err.what();
warning(mLog) << "Failed parsing payload, caught exception: " << err.what();
listen();
return;
}
@@ -215,7 +188,7 @@ struct Measurement
}
else
{
debug(*mLog) << "Received invalid message from " << from;
debug(mLog) << "Received invalid message from " << from;
listen();
}
}
@@ -230,40 +203,40 @@ struct Measurement

try
{
mpSocket->send(buffer.data(), numBytes, to);
mSocket.send(buffer.data(), numBytes, to);
}
catch (const std::runtime_error& err)
{
info(*mLog) << "Failed to send Ping to " << to.address().to_string() << ": "
<< err.what();
info(mLog) << "Failed to send Ping to " << to.address().to_string() << ": "
<< err.what();
}
}

void finish()
{
mTimer->cancel();
mTimer.cancel();
mCallback(std::move(mData));
mData = {};
mSuccess = true;
debug(*mLog) << "Measuring " << mEndpoint << " done.";
debug(mLog) << "Measuring " << mEndpoint << " done.";
}

void fail()
{
mCallback(std::vector<Point>{});
mData = {};
debug(*mLog) << "Measuring " << mEndpoint << " failed.";
debug(mLog) << "Measuring " << mEndpoint << " failed.";
}

std::shared_ptr<Socket> mpSocket;
Socket mSocket;
SessionId mSessionId;
asio::ip::udp::endpoint mEndpoint;
std::vector<std::pair<double, double>> mData;
Callback mCallback;
Clock mClock;
util::Injected<typename IoService::Timer> mTimer;
Timer mTimer;
std::size_t mMeasurementsStarted;
util::Injected<Log> mLog;
Log mLog;
bool mSuccess;
};

@@ -288,7 +261,7 @@ struct Measurement
std::shared_ptr<Impl> mpImpl;
};

std::unique_ptr<IoService> mpIo;
IoContext mIo;
std::shared_ptr<Impl> mpImpl;
};



+ 2
- 4
source/modules/hylia/link/ableton/link/MeasurementEndpointV4.hpp View File

@@ -29,10 +29,8 @@ namespace link

struct MeasurementEndpointV4
{
enum
{
key = 'mep4'
};
static const std::int32_t key = 'mep4';
static_assert(key == 0x6d657034, "Unexpected byte order");

// Model the NetworkByteStreamSerializable concept
friend std::uint32_t sizeInByteStream(const MeasurementEndpointV4 mep)


+ 23
- 36
source/modules/hylia/link/ableton/link/MeasurementService.hpp View File

@@ -19,7 +19,6 @@

#pragma once

#include <ableton/discovery/Socket.hpp>
#include <ableton/link/GhostXForm.hpp>
#include <ableton/link/Kalman.hpp>
#include <ableton/link/LinearRegression.hpp>
@@ -28,48 +27,34 @@
#include <ableton/link/PingResponder.hpp>
#include <ableton/link/SessionId.hpp>
#include <ableton/link/v1/Messages.hpp>
#include <ableton/platforms/asio/AsioService.hpp>
#include <ableton/util/Log.hpp>
#include <map>
#include <memory>
#include <thread>

namespace ableton
{
namespace link
{

template <typename Clock, typename Log>
template <typename Clock, typename IoContext>
class MeasurementService
{
public:
using IoType = util::Injected<IoContext>;
using Point = std::pair<double, double>;

using MeasurementInstance = Measurement<platforms::asio::AsioService,
Clock,
discovery::Socket<v1::kMaxMessageSize>,
Log>;

using MeasurementServicePingResponder = PingResponder<platforms::asio::AsioService&,
Clock,
discovery::Socket<v1::kMaxMessageSize>,
Log>;

static const std::size_t kNumberThreads = 1;
using MeasurementInstance = Measurement<Clock, IoContext>;

MeasurementService(asio::ip::address_v4 address,
SessionId sessionId,
GhostXForm ghostXForm,
Clock clock,
util::Injected<Log> log)
IoType io)
: mClock(std::move(clock))
, mLog(std::move(log))
, mIo(std::move(io))
, mPingResponder(std::move(address),
std::move(sessionId),
std::move(ghostXForm),
util::injectRef(mIo),
mClock,
mLog)
util::injectRef(*mIo))
{
}

@@ -78,10 +63,10 @@ public:

~MeasurementService()
{
// Clear the measurement map in the io service so that whatever
// Clear the measurement map in the IoContext so that whatever
// cleanup code executes in response to the destruction of the
// measurement objects still have access to the io service
mIo.post([this] { mMeasurementMap.clear(); });
// measurement objects still have access to the IoContext.
mIo->async([this] { mMeasurementMap.clear(); });
}

void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)
@@ -100,19 +85,22 @@ public:
{
using namespace std;

mIo.post([this, state, handler] {
mIo->async([this, state, handler] {
const auto nodeId = state.nodeState.nodeId;
auto addr = mPingResponder.endpoint().address().to_v4();
auto callback = CompletionCallback<Handler>{*this, nodeId, handler};

try
{

mMeasurementMap[nodeId] =
MeasurementInstance{state, move(callback), move(addr), mClock, mLog};
std::unique_ptr<MeasurementInstance>(new MeasurementInstance{
state, move(callback), move(addr), mClock, mIo->clone()});
}
catch (const runtime_error& err)
{
info(*mLog) << "Failed to measure. Reason: " << err.what();
info(mIo->log()) << "gateway@" + addr.to_string()
<< " Failed to measure. Reason: " << err.what();
handler(GhostXForm{});
}
});
@@ -142,14 +130,14 @@ private:
using namespace std;
using std::chrono::microseconds;

// Post this to the measurement service's io service so that we
// Post this to the measurement service's IoContext so that we
// don't delete the measurement object in its stack. Capture all
// needed data separately from this, since this object may be
// gone by the time the block gets executed.
auto nodeId = mNodeId;
auto handler = mHandler;
auto& measurementMap = mService.mMeasurementMap;
mService.mIo.post([nodeId, handler, &measurementMap, data] {
auto& measurementMap = mMeasurementService.mMeasurementMap;
mMeasurementService.mIo->async([nodeId, handler, &measurementMap, data] {
const auto it = measurementMap.find(nodeId);
if (it != measurementMap.end())
{
@@ -166,20 +154,19 @@ private:
});
}

MeasurementService& mService;
MeasurementService& mMeasurementService;
NodeId mNodeId;
Handler mHandler;
};

// Make sure the measurement map outlives the io service so that the rest of
// Make sure the measurement map outlives the IoContext so that the rest of
// the members are guaranteed to be valid when any final handlers
// are begin run.
using MeasurementMap = std::map<NodeId, MeasurementInstance>;
using MeasurementMap = std::map<NodeId, std::unique_ptr<MeasurementInstance>>;
MeasurementMap mMeasurementMap;
Clock mClock;
util::Injected<Log> mLog;
platforms::asio::AsioService mIo;
MeasurementServicePingResponder mPingResponder;
IoType mIo;
PingResponder<Clock, IoContext> mPingResponder;
};

} // namespace link


+ 17
- 10
source/modules/hylia/link/ableton/link/NodeState.hpp View File

@@ -22,6 +22,7 @@
#include <ableton/discovery/Payload.hpp>
#include <ableton/link/NodeId.hpp>
#include <ableton/link/SessionId.hpp>
#include <ableton/link/StartStopState.hpp>
#include <ableton/link/Timeline.hpp>

namespace ableton
@@ -31,7 +32,8 @@ namespace link

struct NodeState
{
using Payload = decltype(discovery::makePayload(Timeline{}, SessionMembership{}));
using Payload =
decltype(discovery::makePayload(Timeline{}, SessionMembership{}, StartStopState{}));

NodeId ident() const
{
@@ -40,29 +42,34 @@ struct NodeState

friend bool operator==(const NodeState& lhs, const NodeState& rhs)
{
return std::tie(lhs.nodeId, lhs.sessionId, lhs.timeline)
== std::tie(rhs.nodeId, rhs.sessionId, rhs.timeline);
return std::tie(lhs.nodeId, lhs.sessionId, lhs.timeline, lhs.startStopState)
== std::tie(rhs.nodeId, rhs.sessionId, rhs.timeline, rhs.startStopState);
}

friend Payload toPayload(const NodeState& state)
{
return discovery::makePayload(state.timeline, SessionMembership{state.sessionId});
return discovery::makePayload(
state.timeline, SessionMembership{state.sessionId}, state.startStopState);
}

template <typename It>
static NodeState fromPayload(NodeId id, It begin, It end)
static NodeState fromPayload(NodeId nodeId, It begin, It end)
{
using namespace std;
auto state = NodeState{move(id), {}, {}};
discovery::parsePayload<Timeline, SessionMembership>(move(begin), move(end),
[&state](Timeline tl) { state.timeline = move(tl); },
[&state](SessionMembership sm) { state.sessionId = move(sm.sessionId); });
return state;
auto nodeState = NodeState{move(nodeId), {}, {}, {}};
discovery::parsePayload<Timeline, SessionMembership, StartStopState>(move(begin),
move(end), [&nodeState](Timeline tl) { nodeState.timeline = move(tl); },
[&nodeState](SessionMembership membership) {
nodeState.sessionId = move(membership.sessionId);
},
[&nodeState](StartStopState ststst) { nodeState.startStopState = move(ststst); });
return nodeState;
}

NodeId nodeId;
SessionId sessionId;
Timeline timeline;
StartStopState startStopState;
};

} // namespace link


+ 97
- 0
source/modules/hylia/link/ableton/link/Optional.hpp View File

@@ -0,0 +1,97 @@
/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <cassert>
#include <utility>

namespace ableton
{
namespace link
{

// Subset of the C++ 17 std::optional API. T has to be default constructible.
template <typename T>
struct Optional
{
Optional()
: mHasValue(false)
{
}

explicit Optional(T value)
: mValue(std::move(value))
, mHasValue(true)
{
}

Optional(const Optional&) = default;

Optional(Optional&& other)
: mValue(std::move(other.mValue))
, mHasValue(other.mHasValue)
{
}

Optional& operator=(const Optional&) = default;

Optional& operator=(Optional&& other)
{
mValue = std::move(other.mValue);
mHasValue = other.mHasValue;
return *this;
}

explicit operator bool() const
{
return mHasValue;
}

const T& operator*() const
{
assert(mHasValue);
return mValue;
}

T& operator*()
{
assert(mHasValue);
return mValue;
}

const T* operator->() const
{
assert(mHasValue);
return &mValue;
}

T* operator->()
{
assert(mHasValue);
return &mValue;
}

private:
T mValue;
bool mHasValue;
};

} // namespace link
} // namespace ableton

+ 7
- 13
source/modules/hylia/link/ableton/link/PayloadEntries.hpp View File

@@ -30,10 +30,8 @@ namespace link

struct HostTime
{
enum
{
key = '__ht'
};
static const std::int32_t key = '__ht';
static_assert(key == 0x5f5f6874, "Unexpected byte order");

HostTime() = default;

@@ -66,12 +64,10 @@ struct HostTime
std::chrono::microseconds time;
};

struct GHostTime : HostTime
struct GHostTime
{
enum
{
key = '__gt'
};
static const std::int32_t key = '__gt';
static_assert(key == 0x5f5f6774, "Unexpected byte order");

GHostTime() = default;

@@ -106,10 +102,8 @@ struct GHostTime : HostTime

struct PrevGHostTime
{
enum
{
key = '_pgt'
};
static const std::int32_t key = '_pgt';
static_assert(key == 0x5f706774, "Unexpected byte order");

PrevGHostTime() = default;



+ 5
- 0
source/modules/hylia/link/ableton/link/PeerState.hpp View File

@@ -51,6 +51,11 @@ struct PeerState
return nodeState.timeline;
}

StartStopState startStopState() const
{
return nodeState.startStopState;
}

friend bool operator==(const PeerState& lhs, const PeerState& rhs)
{
return lhs.nodeState == rhs.nodeState && lhs.endpoint == rhs.endpoint;


+ 54
- 12
source/modules/hylia/link/ableton/link/Peers.hpp View File

@@ -33,10 +33,14 @@ namespace link
//
// SessionTimelineCallback is invoked with a session id and a timeline
// whenever a new combination of these values is seen
//
// SessionStartStopStateCallback is invoked with a session id and a startStopState
// whenever a new combination of these values is seen

template <typename IoContext,
typename SessionMembershipCallback,
typename SessionTimelineCallback>
typename SessionTimelineCallback,
typename SessionStartStopStateCallback>
class Peers
{
// non-movable private implementation type
@@ -47,9 +51,10 @@ public:

Peers(util::Injected<IoContext> io,
SessionMembershipCallback membership,
SessionTimelineCallback timeline)
: mpImpl(
std::make_shared<Impl>(std::move(io), std::move(membership), std::move(timeline)))
SessionTimelineCallback timeline,
SessionStartStopStateCallback startStop)
: mpImpl(std::make_shared<Impl>(
std::move(io), std::move(membership), std::move(timeline), std::move(startStop)))
{
}

@@ -196,10 +201,12 @@ private:
{
Impl(util::Injected<IoContext> io,
SessionMembershipCallback membership,
SessionTimelineCallback timeline)
SessionTimelineCallback timeline,
SessionStartStopStateCallback startStop)
: mIo(std::move(io))
, mSessionMembershipCallback(std::move(membership))
, mSessionTimelineCallback(std::move(timeline))
, mSessionStartStopStateCallback(std::move(startStop))
{
}

@@ -209,10 +216,14 @@ private:

const auto peerSession = peerState.sessionId();
const auto peerTimeline = peerState.timeline();
const auto peerStartStopState = peerState.startStopState();
bool isNewSessionTimeline = false;
bool isNewSessionStartStopState = false;
bool didSessionMembershipChange = false;
{
isNewSessionTimeline = !sessionTimelineExists(peerSession, peerTimeline);
isNewSessionStartStopState =
!sessionStartStopStateExists(peerSession, peerStartStopState);

auto peer = make_pair(move(peerState), move(gatewayAddr));
const auto idRange = equal_range(begin(mPeers), end(mPeers), peer, PeerIdComp{});
@@ -254,6 +265,15 @@ private:
mSessionTimelineCallback(peerSession, peerTimeline);
}

// Pass the start stop state to the Controller after it processed the timeline.
// A new timeline can cause a session Id change which will prevent processing the
// new start stop state. By handling the start stop state after the timeline we
// assure that the start stop state is processed with the correct session Id.
if (isNewSessionStartStopState)
{
mSessionStartStopStateCallback(peerSession, peerStartStopState);
}

if (didSessionMembershipChange)
{
mSessionMembershipCallback();
@@ -297,14 +317,29 @@ private:
mSessionMembershipCallback();
}

bool sessionTimelineExists(const SessionId& session, const Timeline& tl)
template <typename Predicate>
bool hasPeerWith(const SessionId& sessionId, Predicate predicate)
{
using namespace std;
return find_if(begin(mPeers), end(mPeers), [&](const Peer& peer) {
return peer.first.sessionId() == session && peer.first.timeline() == tl;
return peer.first.sessionId() == sessionId && predicate(peer.first);
}) != end(mPeers);
}

bool sessionTimelineExists(const SessionId& session, const Timeline& timeline)
{
return hasPeerWith(session,
[&](const PeerState& peerState) { return peerState.timeline() == timeline; });
}

bool sessionStartStopStateExists(
const SessionId& sessionId, const StartStopState& startStopState)
{
return hasPeerWith(sessionId, [&](const PeerState& peerState) {
return peerState.startStopState() == startStopState;
});
}

struct PeerIdComp
{
bool operator()(const Peer& lhs, const Peer& rhs) const
@@ -324,6 +359,7 @@ private:
util::Injected<IoContext> mIo;
SessionMembershipCallback mSessionMembershipCallback;
SessionTimelineCallback mSessionTimelineCallback;
SessionStartStopStateCallback mSessionStartStopStateCallback;
std::vector<Peer> mPeers; // sorted by peerId, unique by (peerId, addr)
};

@@ -342,13 +378,19 @@ private:

template <typename Io,
typename SessionMembershipCallback,
typename SessionTimelineCallback>
Peers<Io, SessionMembershipCallback, SessionTimelineCallback> makePeers(
util::Injected<Io> io,
typename SessionTimelineCallback,
typename SessionStartStopStateCallback>
Peers<Io,
SessionMembershipCallback,
SessionTimelineCallback,
SessionStartStopStateCallback>
makePeers(util::Injected<Io> io,
SessionMembershipCallback membershipCallback,
SessionTimelineCallback timelineCallback)
SessionTimelineCallback timelineCallback,
SessionStartStopStateCallback startStopStateCallback)
{
return {std::move(io), std::move(membershipCallback), std::move(timelineCallback)};
return {std::move(io), std::move(membershipCallback), std::move(timelineCallback),
std::move(startStopStateCallback)};
}

} // namespace link


+ 2
- 2
source/modules/hylia/link/ableton/link/Phase.hpp View File

@@ -96,5 +96,5 @@ inline std::chrono::microseconds fromPhaseEncodedBeats(
return tl.fromBeats(tl.beatOrigin + originOffset + quantum - inversePhaseOffset);
}

} // link
} // ableton
} // namespace link
} // namespace ableton

+ 20
- 23
source/modules/hylia/link/ableton/link/PingResponder.hpp View File

@@ -23,35 +23,34 @@
#include <ableton/link/PayloadEntries.hpp>
#include <ableton/link/SessionId.hpp>
#include <ableton/link/v1/Messages.hpp>
#include <ableton/platforms/asio/AsioWrapper.hpp>
#include <ableton/util/Injected.hpp>
#include <ableton/util/SafeAsyncHandler.hpp>
#include <chrono>
#include <memory>
#include <thread>

namespace ableton
{
namespace link
{

template <typename Io, typename Clock, typename Socket, typename Log>
template <typename Clock, typename IoContext>
class PingResponder
{
using IoType = util::Injected<IoContext&>;
using Socket = typename IoType::type::template Socket<v1::kMaxMessageSize>;

public:
PingResponder(asio::ip::address_v4 address,
SessionId sessionId,
GhostXForm ghostXForm,
util::Injected<Io> io,
Clock clock,
util::Injected<Log> log)
: mIo(std::move(io))
, mpImpl(std::make_shared<Impl>(*mIo,
std::move(address),
IoType io)
: mIo(io)
, mpImpl(std::make_shared<Impl>(std::move(address),
std::move(sessionId),
std::move(ghostXForm),
std::move(clock),
std::move(log)))
std::move(io)))
{
mpImpl->listen();
}
@@ -61,16 +60,16 @@ public:

~PingResponder()
{
// post the release of the impl object into the io service so that
// post the release of the impl object into the IoContext so that
// it happens in the same thread as its handlers
auto pImpl = mpImpl;
mIo->post([pImpl]() mutable { pImpl.reset(); });
mIo->async([pImpl]() mutable { pImpl.reset(); });
}

void updateNodeState(const SessionId& sessionId, const GhostXForm& xform)
{
auto pImpl = mpImpl;
mIo->post([pImpl, sessionId, xform] {
mIo->async([pImpl, sessionId, xform] {
pImpl->mSessionId = std::move(sessionId);
pImpl->mGhostXForm = std::move(xform);
});
@@ -94,19 +93,17 @@ public:
private:
struct Impl : std::enable_shared_from_this<Impl>
{
Impl(typename util::Injected<Io>::type& io,
asio::ip::address_v4 address,
Impl(asio::ip::address_v4 address,
SessionId sessionId,
GhostXForm ghostXForm,
Clock clock,
util::Injected<Log> log)
IoType io)
: mSessionId(std::move(sessionId))
, mGhostXForm(std::move(ghostXForm))
, mClock(std::move(clock))
, mLog(std::move(log))
, mSocket(io)
, mLog(channel(io->log(), "gateway@" + address.to_string()))
, mSocket(io->template openUnicastSocket<v1::kMaxMessageSize>(address))
{
configureUnicastSocket(mSocket, address);
}

void listen()
@@ -131,7 +128,7 @@ private:
sizeInByteStream(makePayload(HostTime{}, PrevGHostTime{}));
if (header.messageType == v1::kPing && payloadSize <= maxPayloadSize)
{
debug(*mLog) << "Received ping message from " << from;
debug(mLog) << " Received ping message from " << from;

try
{
@@ -139,12 +136,12 @@ private:
}
catch (const std::runtime_error& err)
{
info(*mLog) << "Failed to send pong to " << from << ". Reason: " << err.what();
info(mLog) << " Failed to send pong to " << from << ". Reason: " << err.what();
}
}
else
{
info(*mLog) << "Received invalid Message from " << from << ".";
info(mLog) << " Received invalid Message from " << from << ".";
}
listen();
}
@@ -173,11 +170,11 @@ private:
SessionId mSessionId;
GhostXForm mGhostXForm;
Clock mClock;
util::Injected<Log> mLog;
typename IoType::type::Log mLog;
Socket mSocket;
};

util::Injected<Io> mIo;
IoType mIo;
std::shared_ptr<Impl> mpImpl;
};



+ 2
- 4
source/modules/hylia/link/ableton/link/SessionId.hpp View File

@@ -33,10 +33,8 @@ using SessionId = NodeId;
// A payload entry indicating membership in a particular session
struct SessionMembership
{
enum
{
key = 'sess'
};
static const std::int32_t key = 'sess';
static_assert(key == 0x73657373, "Unexpected byte order");

// Model the NetworkByteStreamSerializable concept
friend std::uint32_t sizeInByteStream(const SessionMembership& sm)


+ 80
- 0
source/modules/hylia/link/ableton/link/SessionState.hpp View File

@@ -0,0 +1,80 @@
/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <ableton/link/Optional.hpp>
#include <ableton/link/StartStopState.hpp>
#include <ableton/link/Timeline.hpp>

namespace ableton
{
namespace link
{

using OptionalTimeline = Optional<Timeline>;
using OptionalStartStopState = Optional<StartStopState>;

struct SessionState
{
Timeline timeline;
StartStopState startStopState;
GhostXForm ghostXForm;
};

struct ClientState
{
friend bool operator==(const ClientState& lhs, const ClientState& rhs)
{
return std::tie(lhs.timeline, lhs.startStopState)
== std::tie(rhs.timeline, rhs.startStopState);
}

friend bool operator!=(const ClientState& lhs, const ClientState& rhs)
{
return !(lhs == rhs);
}

Timeline timeline;
StartStopState startStopState;
};

struct RtClientState
{
Timeline timeline;
StartStopState startStopState;
std::chrono::microseconds timelineTimestamp;
std::chrono::microseconds startStopStateTimestamp;
};

struct IncomingClientState
{
OptionalTimeline timeline;
OptionalStartStopState startStopState;
std::chrono::microseconds timelineTimestamp;
};

struct ApiState
{
Timeline timeline;
ApiStartStopState startStopState;
};

} // namespace link
} // namespace ableton

+ 3
- 2
source/modules/hylia/link/ableton/link/Sessions.hpp View File

@@ -159,8 +159,9 @@ private:
range.first->measurement = move(measurement);
// If session times too close - fall back to session id order
const auto ghostDiff = newGhost - curGhost;
if (ghostDiff > SESSION_EPS || (std::abs(ghostDiff.count()) < SESSION_EPS.count()
&& id < mCurrent.sessionId))
if (ghostDiff > SESSION_EPS
|| (std::abs(ghostDiff.count()) < SESSION_EPS.count()
&& id < mCurrent.sessionId))
{
// The new session wins, switch over to it
auto current = mCurrent;


+ 123
- 0
source/modules/hylia/link/ableton/link/StartStopState.hpp View File

@@ -0,0 +1,123 @@
/* Copyright 2017, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <ableton/discovery/NetworkByteStreamSerializable.hpp>
#include <ableton/link/Beats.hpp>
#include <chrono>
#include <tuple>

namespace ableton
{
namespace link
{

// A tuple of (isPlaying, time) that represents the playing state
// with an according timestamp in microseconds. It also serves as a
// payload entry.

struct StartStopState
{
static const std::int32_t key = 'stst';
static_assert(key == 0x73747374, "Unexpected byte order");

using StartStopStateTuple = std::tuple<bool, Beats, std::chrono::microseconds>;

StartStopState() = default;

StartStopState(
const bool aIsPlaying, const Beats aBeats, const std::chrono::microseconds aTimestamp)
: isPlaying(aIsPlaying)
, beats(aBeats)
, timestamp(aTimestamp)
{
}

friend bool operator==(const StartStopState& lhs, const StartStopState& rhs)
{
return std::tie(lhs.isPlaying, lhs.beats, lhs.timestamp)
== std::tie(rhs.isPlaying, rhs.beats, rhs.timestamp);
}

friend bool operator!=(const StartStopState& lhs, const StartStopState& rhs)
{
return !(lhs == rhs);
}

// Model the NetworkByteStreamSerializable concept
friend std::uint32_t sizeInByteStream(const StartStopState& state)
{
return discovery::sizeInByteStream(state.asTuple());
}

template <typename It>
friend It toNetworkByteStream(const StartStopState& state, It out)
{
return discovery::toNetworkByteStream(state.asTuple(), std::move(out));
}

template <typename It>
static std::pair<StartStopState, It> fromNetworkByteStream(It begin, It end)
{
using namespace std;
using namespace discovery;
auto result =
Deserialize<StartStopStateTuple>::fromNetworkByteStream(move(begin), move(end));
auto state =
StartStopState{get<0>(result.first), get<1>(result.first), get<2>(result.first)};
return make_pair(move(state), move(result.second));
}

bool isPlaying{false};
Beats beats{0.};
std::chrono::microseconds timestamp{0};

private:
StartStopStateTuple asTuple() const
{
return std::make_tuple(isPlaying, beats, timestamp);
}
};

struct ApiStartStopState
{
ApiStartStopState() = default;

ApiStartStopState(const bool aIsPlaying, const std::chrono::microseconds aTime)
: isPlaying(aIsPlaying)
, time(aTime)
{
}

friend bool operator==(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
{
return std::tie(lhs.isPlaying, lhs.time) == std::tie(rhs.isPlaying, rhs.time);
}

friend bool operator!=(const ApiStartStopState& lhs, const ApiStartStopState& rhs)
{
return !(lhs == rhs);
}

bool isPlaying{false};
std::chrono::microseconds time{0};
};
} // namespace link
} // namespace ableton

+ 2
- 4
source/modules/hylia/link/ableton/link/Timeline.hpp View File

@@ -38,10 +38,8 @@ namespace link

struct Timeline
{
enum
{
key = 'tmln'
};
static const std::int32_t key = 'tmln';
static_assert(key == 0x746d6c6e, "Unexpected byte order");

Beats toBeats(const std::chrono::microseconds time) const
{


+ 11
- 14
source/modules/hylia/link/ableton/platforms/Config.hpp View File

@@ -22,15 +22,15 @@
#include <ableton/link/Controller.hpp>
#include <ableton/util/Log.hpp>

#if LINK_PLATFORM_WINDOWS
#if defined(LINK_PLATFORM_WINDOWS)
#include <ableton/platforms/asio/Context.hpp>
#include <ableton/platforms/windows/Clock.hpp>
#include <ableton/platforms/windows/ScanIpIfAddrs.hpp>
#elif LINK_PLATFORM_MACOSX
#elif defined(LINK_PLATFORM_MACOSX)
#include <ableton/platforms/asio/Context.hpp>
#include <ableton/platforms/darwin/Clock.hpp>
#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>
#elif LINK_PLATFORM_LINUX
#elif defined(LINK_PLATFORM_LINUX)
#include <ableton/platforms/asio/Context.hpp>
#include <ableton/platforms/linux/Clock.hpp>
#include <ableton/platforms/posix/ScanIpIfAddrs.hpp>
@@ -43,28 +43,25 @@ namespace link
namespace platform
{

#if LINK_PLATFORM_WINDOWS
#if defined(LINK_PLATFORM_WINDOWS)
using Clock = platforms::windows::Clock;
using IoContext =
platforms::asio::Context<platforms::windows::ScanIpIfAddrs, util::NullLog>;

#elif LINK_PLATFORM_MACOSX
#elif defined(LINK_PLATFORM_MACOSX)
using Clock = platforms::darwin::Clock;
using IoContext =
platforms::asio::Context<platforms::posix::ScanIpIfAddrs, util::NullLog>;

#elif LINK_PLATFORM_LINUX
#ifdef __ARM_ARCH_7A__
using Clock = platforms::linux::ClockMonotonicRaw;
#else
#elif defined(LINK_PLATFORM_LINUX)
using Clock = platforms::linux::ClockMonotonic;
#endif
using IoContext =
platforms::asio::Context<platforms::posix::ScanIpIfAddrs, util::NullLog>;
#endif

using Controller = Controller<PeerCountCallback, TempoCallback, Clock, IoContext>;
using Controller =
Controller<PeerCountCallback, TempoCallback, StartStopStateCallback, Clock, IoContext>;

} // platform
} // link
} // ableton
} // namespace platform
} // namespace link
} // namespace ableton

+ 0
- 105
source/modules/hylia/link/ableton/platforms/asio/AsioService.hpp View File

@@ -1,105 +0,0 @@
/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <ableton/platforms/asio/AsioTimer.hpp>
#include <ableton/platforms/asio/AsioWrapper.hpp>
#include <thread>

namespace ableton
{
namespace platforms
{
namespace asio
{

class AsioService
{
public:
using Timer = AsioTimer;

AsioService()
: AsioService(DefaultHandler{})
{
}

template <typename ExceptionHandler>
explicit AsioService(ExceptionHandler exceptHandler)
: mpWork(new ::asio::io_service::work(mService))
{
mThread =
std::thread{[](::asio::io_service& service, ExceptionHandler handler) {
for (;;)
{
try
{
service.run();
break;
}
catch (const typename ExceptionHandler::Exception& exception)
{
handler(exception);
}
}
},
std::ref(mService), std::move(exceptHandler)};
}

~AsioService()
{
mpWork.reset();
mThread.join();
}

AsioTimer makeTimer()
{
return {mService};
}

template <typename Handler>
void post(Handler handler)
{
mService.post(std::move(handler));
}

::asio::io_service mService;

private:
// Default handler is hidden and defines a hidden exception type
// that will never be thrown by other code, so it effectively does
// not catch.
struct DefaultHandler
{
struct Exception
{
};

void operator()(const Exception&)
{
}
};

std::unique_ptr<::asio::io_service::work> mpWork;
std::thread mThread;
};

} // namespace asio
} // namespace platforms
} // namespace ableton

+ 19
- 12
source/modules/hylia/link/ableton/platforms/asio/AsioWrapper.hpp View File

@@ -32,35 +32,41 @@
#pragma push_macro("ASIO_NO_TYPEID")
#define ASIO_NO_TYPEID 1

#if LINK_PLATFORM_WINDOWS
#if defined(LINK_PLATFORM_WINDOWS)
#pragma push_macro("INCL_EXTRA_HTON_FUNCTIONS")
#define INCL_EXTRA_HTON_FUNCTIONS 1
#endif

#if defined(WIN32) || defined(_WIN32)
#if !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x0501
#endif
#endif

#if defined(__clang__)
#pragma clang diagnostic push
#if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma"
#endif
#if __has_warning("-Wshorten-64-to-32")
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
#endif
#if __has_warning("-Wunused-local-typedef")
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#endif

#if defined(_MSC_VER)
#pragma warning(push)
// C4191: 'operator/operation': unsafe conversion from 'type of expression' to
// 'type required'
#pragma warning(disable : 4191)
// C4548: expression before comma has no effect; expected expression with side-effect
#pragma warning(disable : 4548)
// C4619: #pragma warning : there is no warning number 'number'
#pragma warning(disable : 4619)
// C4675: 'function' : resolved overload was found by argument-dependent lookup
#pragma warning(disable : 4675)
#define _SCL_SECURE_NO_WARNINGS 1
#pragma warning(push, 0)
#pragma warning(disable : 4242)
#pragma warning(disable : 4702)
#endif

#include <asio.hpp>
#include <asio/system_timer.hpp>

#if LINK_PLATFORM_WINDOWS
#if defined(LINK_PLATFORM_WINDOWS)
#pragma pop_macro("INCL_EXTRA_HTON_FUNCTIONS")
#endif

@@ -69,6 +75,7 @@

#if defined(_MSC_VER)
#pragma warning(pop)
#undef _SCL_SECURE_NO_WARNINGS
#endif

#if defined(__clang__)


+ 2
- 2
source/modules/hylia/link/ableton/platforms/asio/LockFreeCallbackDispatcher.hpp View File

@@ -85,5 +85,5 @@ private:
std::thread mThread;
};

} // platforms
} // ableton
} // namespace platforms
} // namespace ableton

+ 3
- 3
source/modules/hylia/link/ableton/platforms/asio/Util.hpp View File

@@ -38,6 +38,6 @@ AsioAddrType makeAddress(const char* pAddr)
return AsioAddrType{bytes};
}

} // asio
} // platforms
} // ableton
} // namespace asio
} // namespace platforms
} // namespace ableton

+ 0
- 10
source/modules/hylia/link/ableton/platforms/linux/Clock.hpp View File

@@ -49,17 +49,7 @@ public:
};

using ClockMonotonic = Clock<CLOCK_MONOTONIC>;
#ifdef CLOCK_MONOTONIC_RAW
using ClockMonotonicRaw = Clock<CLOCK_MONOTONIC_RAW>;
#endif

/* Warning: the realtime clock can be subject to time change.
* One of the hard requirements of Ableton Link is that the clock must be
* monotonic.
* Only use the Realtime Clock if you can't use the monotonic ones, and
* beware that things might go wrong if time jumps.
*/
using ClockRealtime = Clock<CLOCK_REALTIME>;

} // namespace linux
} // namespace platforms


+ 1
- 1
source/modules/hylia/link/ableton/platforms/posix/ScanIpIfAddrs.hpp View File

@@ -67,7 +67,7 @@ private:
struct ifaddrs* interfaces = NULL;
};

} // detail
} // namespace detail


// Posix implementation of ip interface address scanner


+ 1
- 1
source/modules/hylia/link/ableton/platforms/windows/ScanIpIfAddrs.hpp View File

@@ -93,7 +93,7 @@ private:
IP_ADAPTER_ADDRESSES* adapter;
};

} // detail
} // namespace detail

struct ScanIpIfAddrs
{


+ 3
- 6
source/modules/hylia/link/ableton/test/CatchWrapper.hpp View File

@@ -26,18 +26,15 @@
* which are specific to that library.
*/

// Visual Studio
#if defined(_MSC_VER)
#pragma warning(push)
// C4388: signed/unsigned mismatch
#pragma warning(disable : 4388)
// C4702: unreachable code
#pragma warning(push, 0)
#pragma warning(disable : 4242)
#pragma warning(disable : 4244)
#pragma warning(disable : 4702)
#endif

#include <catch.hpp>

// Visual Studio
#if defined(_MSC_VER)
#pragma warning(pop)
#endif

+ 0
- 83
source/modules/hylia/link/ableton/test/serial_io/Socket.hpp View File

@@ -1,83 +0,0 @@
/* Copyright 2016, Ableton AG, Berlin. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* If you would like to incorporate Link into a proprietary software application,
* please contact <link-devs@ableton.com>.
*/

#pragma once

#include <ableton/platforms/AsioWrapper.hpp>
#include <functional>

namespace ableton
{
namespace test
{
namespace serial_io
{

struct Socket
{
using SendFn = std::function<std::size_t(
const uint8_t* const, const size_t, const asio::ip::udp::endpoint&)>;

struct ReceiveHandler
{
template <typename It>
void operator()(const asio::ip::udp::endpoint& from, const It begin, const It end)
{
std::vector<uint8_t> buffer{begin, end};
mReceive(from, buffer);
}

std::function<const asio::ip::udp::endpoint&, const std::vector<uint8_t>&> mReceive;
};

using ReceiveFn = std::function<void(ReceiveHandler)>;

Socket(SendFn sendFn, ReceiveFn receiveFn)
: mSendFn(std::move(sendFn))
, mReceiveFn(std::move(receiveFn))
{
}

std::size_t send(
const uint8_t* const pData, const size_t numBytes, const asio::ip::udp::endpoint& to)
{
return mSendFn(pData, numBytes, to);
}

template <typename Handler>
void receive(Handler handler)
{
mReceiveFn(ReceiveHandler{
[handler](const asio::ip::udp::endpoint& from, const std::vector<uint8_t>& buffer) {
handler(from, begin(buffer), end(buffer));
}});
}

asio::ip::udp::endpoint endpoint() const
{
return asio::ip::udp::endpoint({}, 0);
}

SendFn mSendFn;
ReceiveFn mReceiveFn;
};

} // namespace test
} // namespace platforms
} // namespace ableton

+ 2
- 2
source/modules/hylia/link/ableton/util/SampleTiming.hpp View File

@@ -48,5 +48,5 @@ struct SampleTiming
double mSampleRate;
};

} // util
} // ableton
} // namespace util
} // namespace ableton

+ 20
- 17
source/modules/hylia/link/asio.hpp View File

@@ -2,7 +2,7 @@
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -18,6 +18,7 @@
#include "asio/associated_allocator.hpp"
#include "asio/associated_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/awaitable.hpp"
#include "asio/basic_datagram_socket.hpp"
#include "asio/basic_deadline_timer.hpp"
#include "asio/basic_io_object.hpp"
@@ -25,6 +26,7 @@
#include "asio/basic_seq_packet_socket.hpp"
#include "asio/basic_serial_port.hpp"
#include "asio/basic_signal_set.hpp"
#include "asio/basic_socket.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp"
@@ -40,13 +42,14 @@
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffers_iterator.hpp"
#include "asio/co_spawn.hpp"
#include "asio/completion_condition.hpp"
#include "asio/compose.hpp"
#include "asio/connect.hpp"
#include "asio/coroutine.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/deadline_timer.hpp"
#include "asio/defer.hpp"
#include "asio/detached.hpp"
#include "asio/dispatch.hpp"
#include "asio/error.hpp"
#include "asio/error_code.hpp"
@@ -61,7 +64,7 @@
#include "asio/handler_alloc_hook.hpp"
#include "asio/handler_continuation_hook.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/handler_type.hpp"
#include "asio/high_resolution_timer.hpp"
#include "asio/io_context.hpp"
#include "asio/io_context_strand.hpp"
#include "asio/io_service.hpp"
@@ -73,6 +76,8 @@
#include "asio/ip/address_v6.hpp"
#include "asio/ip/address_v6_iterator.hpp"
#include "asio/ip/address_v6_range.hpp"
#include "asio/ip/network_v4.hpp"
#include "asio/ip/network_v6.hpp"
#include "asio/ip/bad_address_cast.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
@@ -84,7 +89,6 @@
#include "asio/ip/multicast.hpp"
#include "asio/ip/resolver_base.hpp"
#include "asio/ip/resolver_query_base.hpp"
#include "asio/ip/resolver_service.hpp"
#include "asio/ip/tcp.hpp"
#include "asio/ip/udp.hpp"
#include "asio/ip/unicast.hpp"
@@ -96,48 +100,47 @@
#include "asio/local/connect_pair.hpp"
#include "asio/local/datagram_protocol.hpp"
#include "asio/local/stream_protocol.hpp"
#include "asio/packaged_task.hpp"
#include "asio/placeholders.hpp"
#include "asio/posix/basic_descriptor.hpp"
#include "asio/posix/basic_stream_descriptor.hpp"
#include "asio/posix/descriptor.hpp"
#include "asio/posix/descriptor_base.hpp"
#include "asio/posix/stream_descriptor.hpp"
#include "asio/posix/stream_descriptor_service.hpp"
#include "asio/post.hpp"
#include "asio/raw_socket_service.hpp"
#include "asio/read.hpp"
#include "asio/read_at.hpp"
#include "asio/read_until.hpp"
#include "asio/seq_packet_socket_service.hpp"
#include "asio/redirect_error.hpp"
#include "asio/serial_port.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#include "asio/signal_set.hpp"
#include "asio/signal_set_service.hpp"
#include "asio/socket_acceptor_service.hpp"
#include "asio/socket_base.hpp"
#include "asio/steady_timer.hpp"
#include "asio/strand.hpp"
#include "asio/stream_socket_service.hpp"
#include "asio/streambuf.hpp"
#include "asio/system_context.hpp"
#include "asio/system_error.hpp"
#include "asio/system_executor.hpp"
#include "asio/system_timer.hpp"
#include "asio/this_coro.hpp"
#include "asio/thread.hpp"
#include "asio/thread_pool.hpp"
#include "asio/time_traits.hpp"
#include "asio/use_awaitable.hpp"
#include "asio/use_future.hpp"
#include "asio/uses_executor.hpp"
#include "asio/version.hpp"
#include "asio/wait_traits.hpp"
#include "asio/waitable_timer_service.hpp"
#include "asio/windows/basic_handle.hpp"
#include "asio/windows/basic_object_handle.hpp"
#include "asio/windows/basic_overlapped_handle.hpp"
#include "asio/windows/basic_random_access_handle.hpp"
#include "asio/windows/basic_stream_handle.hpp"
#include "asio/windows/object_handle.hpp"
#include "asio/windows/object_handle_service.hpp"
#include "asio/windows/overlapped_handle.hpp"
#include "asio/windows/overlapped_ptr.hpp"
#include "asio/windows/random_access_handle.hpp"
#include "asio/windows/random_access_handle_service.hpp"
#include "asio/windows/stream_handle.hpp"
#include "asio/windows/stream_handle_service.hpp"
#include "asio/write.hpp"
#include "asio/write_at.hpp"



+ 9
- 1
source/modules/hylia/link/asio/associated_allocator.hpp View File

@@ -2,7 +2,7 @@
// associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -116,6 +116,14 @@ get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT
return associated_allocator<T, Allocator>::get(t, a);
}

#if defined(ASIO_HAS_ALIAS_TEMPLATES)

template <typename T, typename Allocator = std::allocator<void> >
using associated_allocator_t
= typename associated_allocator<T, Allocator>::type;

#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)

} // namespace asio

#include "asio/detail/pop_options.hpp"


+ 8
- 1
source/modules/hylia/link/asio/associated_executor.hpp View File

@@ -2,7 +2,7 @@
// associated_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -135,6 +135,13 @@ get_associated_executor(const T& t, ExecutionContext& ctx,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}

#if defined(ASIO_HAS_ALIAS_TEMPLATES)

template <typename T, typename Executor = system_executor>
using associated_executor_t = typename associated_executor<T, Executor>::type;

#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)

} // namespace asio

#include "asio/detail/pop_options.hpp"


+ 275
- 44
source/modules/hylia/link/asio/async_result.hpp View File

@@ -2,7 +2,7 @@
// async_result.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -17,7 +17,7 @@

#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/handler_type.hpp"
#include "asio/detail/variadic_templates.hpp"

#include "asio/detail/push_options.hpp"

@@ -25,58 +25,134 @@ namespace asio {

/// An interface for customising the behaviour of an initiating function.
/**
* This template may be specialised for user-defined handler types.
* The async_result traits class is used for determining:
*
* @li the concrete completion handler type to be called at the end of the
* asynchronous operation;
*
* @li the initiating function return type; and
*
* @li how the return value of the initiating function is obtained.
*
* The trait allows the handler and return types to be determined at the point
* where the specific completion handler signature is known.
*
* This template may be specialised for user-defined completion token types.
* The primary template assumes that the CompletionToken is the completion
* handler.
*/
template <typename Handler>
template <typename CompletionToken, typename Signature>
class async_result
{
public:
/// The concrete completion handler type for the specific signature.
typedef CompletionToken completion_handler_type;

/// The return type of the initiating function.
typedef void type;
typedef void return_type;

/// Construct an async result from a given handler.
/**
* When using a specalised async_result, the constructor has an opportunity
* to initialise some state associated with the handler, which is then
* returned from the initiating function.
* to initialise some state associated with the completion handler, which is
* then returned from the initiating function.
*/
explicit async_result(Handler&)
explicit async_result(completion_handler_type& h)
{
(void)h;
}

/// Obtain the value to be returned from the initiating function.
type get()
return_type get()
{
}

#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
|| defined(GENERATING_DOCUMENTATION)

/// Initiate the asynchronous operation that will produce the result, and
/// obtain the value to be returned from the initiating function.
template <typename Initiation, typename RawCompletionToken, typename... Args>
static return_type initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_CAST(Initiation)(initiation)(
ASIO_MOVE_CAST(RawCompletionToken)(token),
ASIO_MOVE_CAST(Args)(args)...);
}

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)

template <typename Initiation, typename RawCompletionToken>
static return_type initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token)
{
ASIO_MOVE_CAST(Initiation)(initiation)(
ASIO_MOVE_CAST(RawCompletionToken)(token));
}

#define ASIO_PRIVATE_INITIATE_DEF(n) \
template <typename Initiation, typename RawCompletionToken, \
ASIO_VARIADIC_TPARAMS(n)> \
static return_type initiate( \
ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_MOVE_ARG(RawCompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
ASIO_MOVE_CAST(Initiation)(initiation)( \
ASIO_MOVE_CAST(RawCompletionToken)(token), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
#undef ASIO_PRIVATE_INITIATE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)

private:
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;
};

/// Helper template to deduce the real type of a handler, capture a local copy
/// of the handler, and then create an async_result for the handler.
template <typename Handler, typename Signature>
/// Helper template to deduce the handler type from a CompletionToken, capture
/// a local copy of the handler, and then create an async_result for the
/// handler.
template <typename CompletionToken, typename Signature>
struct async_completion
{
/// The real handler type to be used for the asynchronous operation.
typedef typename asio::handler_type<
Handler, Signature>::type handler_type;
typedef typename asio::async_result<
typename decay<CompletionToken>::type,
Signature>::completion_handler_type completion_handler_type;

#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Constructor.
/**
* The constructor creates the concrete handler and makes the link between
* the handler and the asynchronous result.
* The constructor creates the concrete completion handler and makes the link
* between the handler and the asynchronous result.
*/
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
explicit async_completion(
Handler& orig_handler)
: handler(static_cast<typename conditional<
is_same<Handler, handler_type>::value,
handler_type&, Handler&&>::type>(orig_handler)),
result(handler)
explicit async_completion(CompletionToken& token)
: completion_handler(static_cast<typename conditional<
is_same<CompletionToken, completion_handler_type>::value,
completion_handler_type&, CompletionToken&&>::type>(token)),
result(completion_handler)
{
}
#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
explicit async_completion(const Handler& orig_handler)
: handler(orig_handler),
result(handler)
explicit async_completion(typename decay<CompletionToken>::type& token)
: completion_handler(token),
result(completion_handler)
{
}

explicit async_completion(const typename decay<CompletionToken>::type& token)
: completion_handler(token),
result(completion_handler)
{
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
@@ -84,42 +160,197 @@ struct async_completion
/// A copy of, or reference to, a real handler object.
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
typename conditional<
is_same<Handler, handler_type>::value,
handler_type&, handler_type>::type handler;
is_same<CompletionToken, completion_handler_type>::value,
completion_handler_type&, completion_handler_type>::type completion_handler;
#else // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
typename asio::handler_type<Handler, Signature>::type handler;
completion_handler_type completion_handler;
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// The result of the asynchronous operation's initiating function.
async_result<typename asio::handler_type<
Handler, Signature>::type> result;
async_result<typename decay<CompletionToken>::type, Signature> result;
};

namespace detail {

template <typename Handler, typename Signature>
struct async_result_type_helper
template <typename CompletionToken, typename Signature>
struct async_result_helper
: async_result<typename decay<CompletionToken>::type, Signature>
{
typedef typename async_result<
typename handler_type<Handler, Signature>::type
>::type type;
};

} // namespace detail
} // namespace asio
struct async_result_memfns_base
{
void initiate();
};

#include "asio/detail/pop_options.hpp"
template <typename T>
struct async_result_memfns_derived
: T, async_result_memfns_base
{
};

template <typename T, T>
struct async_result_memfns_check
{
};

template <typename>
char (&async_result_initiate_memfn_helper(...))[2];

template <typename T>
char async_result_initiate_memfn_helper(
async_result_memfns_check<
void (async_result_memfns_base::*)(),
&async_result_memfns_derived<T>::initiate>*);

template <typename CompletionToken, typename Signature>
struct async_result_has_initiate_memfn
: integral_constant<bool, sizeof(async_result_initiate_memfn_helper<
async_result<typename decay<CompletionToken>::type, Signature>
>(0)) != 1>
{
};

} // namespace detail

#if defined(GENERATING_DOCUMENTATION)
# define ASIO_INITFN_RESULT_TYPE(h, sig) \
# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
void_or_deduced
#elif defined(_MSC_VER) && (_MSC_VER < 1500)
# define ASIO_INITFN_RESULT_TYPE(h, sig) \
typename ::asio::detail::async_result_type_helper<h, sig>::type
# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
typename ::asio::detail::async_result_helper< \
ct, sig>::return_type
#define ASIO_HANDLER_TYPE(ct, sig) \
typename ::asio::detail::async_result_helper< \
ct, sig>::completion_handler_type
#else
# define ASIO_INITFN_RESULT_TYPE(h, sig) \
# define ASIO_INITFN_RESULT_TYPE(ct, sig) \
typename ::asio::async_result< \
typename ::asio::decay<ct>::type, sig>::return_type
#define ASIO_HANDLER_TYPE(ct, sig) \
typename ::asio::async_result< \
typename ::asio::handler_type<h, sig>::type>::type
typename ::asio::decay<ct>::type, sig>::completion_handler_type
#endif

#if defined(GENERATING_DOCUMENTATION)

template <typename CompletionToken, typename Signature,
typename Initiation, typename... Args>
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken),
ASIO_MOVE_ARG(Args)... args);

#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename CompletionToken, typename Signature,
typename Initiation, typename... Args>
inline typename enable_if<
detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
return async_result<typename decay<CompletionToken>::type,
Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),
ASIO_MOVE_CAST(CompletionToken)(token),
ASIO_MOVE_CAST(Args)(args)...);
}

template <typename CompletionToken, typename Signature,
typename Initiation, typename... Args>
inline typename enable_if<
!detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
async_completion<CompletionToken, Signature> completion(token);

ASIO_MOVE_CAST(Initiation)(initiation)(
ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,
Signature))(completion.completion_handler),
ASIO_MOVE_CAST(Args)(args)...);

return completion.result.get();
}

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)

template <typename CompletionToken, typename Signature, typename Initiation>
inline typename enable_if<
detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)
{
return async_result<typename decay<CompletionToken>::type,
Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation),
ASIO_MOVE_CAST(CompletionToken)(token));
}

template <typename CompletionToken, typename Signature, typename Initiation>
inline typename enable_if<
!detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value,
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type
async_initiate(ASIO_MOVE_ARG(Initiation) initiation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token)
{
async_completion<CompletionToken, Signature> completion(token);

ASIO_MOVE_CAST(Initiation)(initiation)(
ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken,
Signature))(completion.completion_handler));

return completion.result.get();
}

#define ASIO_PRIVATE_INITIATE_DEF(n) \
template <typename CompletionToken, typename Signature, \
typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \
inline typename enable_if< \
detail::async_result_has_initiate_memfn< \
CompletionToken, Signature>::value, \
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \
async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return async_result<typename decay<CompletionToken>::type, \
Signature>::initiate(ASIO_MOVE_CAST(Initiation)(initiation), \
ASIO_MOVE_CAST(CompletionToken)(token), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <typename CompletionToken, typename Signature, \
typename Initiation, ASIO_VARIADIC_TPARAMS(n)> \
inline typename enable_if< \
!detail::async_result_has_initiate_memfn< \
CompletionToken, Signature>::value, \
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \
async_initiate(ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
async_completion<CompletionToken, Signature> completion(token); \
\
ASIO_MOVE_CAST(Initiation)(initiation)( \
ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(CompletionToken, \
Signature))(completion.completion_handler), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
\
return completion.result.get(); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
#undef ASIO_PRIVATE_INITIATE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_ASYNC_RESULT_HPP

+ 123
- 0
source/modules/hylia/link/asio/awaitable.hpp View File

@@ -0,0 +1,123 @@
//
// awaitable.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_AWAITABLE_HPP
#define ASIO_AWAITABLE_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"

#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)

#include <experimental/coroutine>
#include "asio/executor.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace detail {

using std::experimental::coroutine_handle;
using std::experimental::suspend_always;

template <typename> class awaitable_thread;
template <typename, typename> class awaitable_frame;

} // namespace detail

/// The return type of a coroutine or asynchronous operation.
template <typename T, typename Executor = executor>
class awaitable
{
public:
/// The type of the awaited value.
typedef T value_type;

/// The executor type that will be used for the coroutine.
typedef Executor executor_type;

/// Default constructor.
constexpr awaitable() noexcept
: frame_(nullptr)
{
}

/// Move constructor.
awaitable(awaitable&& other) noexcept
: frame_(std::exchange(other.frame_, nullptr))
{
}

/// Destructor
~awaitable()
{
if (frame_)
frame_->destroy();
}

/// Checks if the awaitable refers to a future result.
bool valid() const noexcept
{
return !!frame_;
}

#if !defined(GENERATING_DOCUMENTATION)

// Support for co_await keyword.
bool await_ready() const noexcept
{
return false;
}

// Support for co_await keyword.
template <class U>
void await_suspend(
detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
{
frame_->push_frame(&h.promise());
}

// Support for co_await keyword.
T await_resume()
{
return frame_->get();
}

#endif // !defined(GENERATING_DOCUMENTATION)

private:
template <typename> friend class detail::awaitable_thread;
template <typename, typename> friend class detail::awaitable_frame;

// Not copy constructible or copy assignable.
awaitable(const awaitable&) = delete;
awaitable& operator=(const awaitable&) = delete;

// Construct the awaitable from a coroutine's frame object.
explicit awaitable(detail::awaitable_frame<T, Executor>* a)
: frame_(a)
{
}

detail::awaitable_frame<T, Executor>* frame_;
};

} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/impl/awaitable.hpp"

#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)

#endif // ASIO_AWAITABLE_HPP

+ 320
- 150
source/modules/hylia/link/asio/basic_datagram_socket.hpp View File

@@ -2,7 +2,7 @@
// basic_datagram_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -18,8 +18,8 @@
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/basic_socket.hpp"
#include "asio/datagram_socket_service.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
@@ -28,6 +28,15 @@

namespace asio {

#if !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)
#define ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_datagram_socket;

#endif // !defined(ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL)

/// Provides datagram-oriented socket functionality.
/**
* The basic_datagram_socket class template provides asynchronous and blocking
@@ -37,14 +46,29 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename DatagramSocketService = datagram_socket_service<Protocol> >
template <typename Protocol, typename Executor>
class basic_datagram_socket
: public basic_socket<Protocol, DatagramSocketService>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_datagram_socket<Protocol, Executor1> other;
};

/// The native representation of a socket.
typedef typename DatagramSocketService::native_handle_type native_handle_type;
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif

/// The protocol type.
typedef Protocol protocol_type;
@@ -57,12 +81,29 @@ public:
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_datagram_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}

/// Construct a basic_datagram_socket without opening it.
/**
* This constructor creates a datagram socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
explicit basic_datagram_socket(asio::io_context& io_context)
: basic_socket<Protocol, DatagramSocketService>(io_context)
template <typename ExecutionContext>
explicit basic_datagram_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}

@@ -70,17 +111,37 @@ public:
/**
* This constructor creates and opens a datagram socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}

/// Construct and open a basic_datagram_socket.
/**
* This constructor creates and opens a datagram socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol, DatagramSocketService>(io_context, protocol)
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}

@@ -91,18 +152,42 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol, DatagramSocketService>(io_context, endpoint)
basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}

/// Construct a basic_datagram_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a datagram socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the datagram
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}

@@ -111,9 +196,8 @@ public:
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param io_context The io_context object that the datagram socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@@ -121,10 +205,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_datagram_socket(asio::io_context& io_context,
basic_datagram_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, DatagramSocketService>(
io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}

/// Construct a basic_datagram_socket on an existing native socket.
/**
* This constructor creates a datagram socket object to hold an existing
* native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_datagram_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}

@@ -137,11 +245,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
basic_datagram_socket(basic_datagram_socket&& other)
: basic_socket<Protocol, DatagramSocketService>(
ASIO_MOVE_CAST(basic_datagram_socket)(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -154,12 +262,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
basic_datagram_socket& operator=(basic_datagram_socket&& other)
{
basic_socket<Protocol, DatagramSocketService>::operator=(
ASIO_MOVE_CAST(basic_datagram_socket)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}

@@ -172,15 +280,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename DatagramSocketService1>
basic_datagram_socket(
basic_datagram_socket<Protocol1, DatagramSocketService1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol, DatagramSocketService>(
ASIO_MOVE_CAST2(basic_datagram_socket<
Protocol1, DatagramSocketService1>)(other))
template <typename Protocol1, typename Executor1>
basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -194,20 +303,30 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_datagram_socket(io_context&) constructor.
* constructed using the @c basic_datagram_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename DatagramSocketService1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_datagram_socket>::type& operator=(
basic_datagram_socket<Protocol1, DatagramSocketService1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_datagram_socket&
>::type operator=(basic_datagram_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, DatagramSocketService>::operator=(
ASIO_MOVE_CAST2(basic_datagram_socket<
Protocol1, DatagramSocketService1>)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_datagram_socket()
{
}

/// Send some data on a connected socket.
/**
* This function is used to send data on the datagram socket. The function
@@ -234,8 +353,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -262,8 +381,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -289,8 +408,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().send(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous send on a connected socket.
@@ -311,9 +430,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
@@ -334,12 +453,10 @@ public:
async_send(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous send on a connected socket.
@@ -362,9 +479,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected datagram
@@ -377,12 +494,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this, buffers, flags);
}

/// Send a datagram to the specified endpoint.
@@ -415,8 +529,8 @@ public:
const endpoint_type& destination)
{
asio::error_code ec;
std::size_t s = this->get_service().send_to(
this->get_implementation(), buffers, destination, 0, ec);
std::size_t s = this->impl_.get_service().send_to(
this->impl_.get_implementation(), buffers, destination, 0, ec);
asio::detail::throw_error(ec, "send_to");
return s;
}
@@ -442,8 +556,8 @@ public:
const endpoint_type& destination, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send_to(
this->get_implementation(), buffers, destination, flags, ec);
std::size_t s = this->impl_.get_service().send_to(
this->impl_.get_implementation(), buffers, destination, flags, ec);
asio::detail::throw_error(ec, "send_to");
return s;
}
@@ -469,7 +583,7 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->get_service().send_to(this->get_implementation(),
return this->impl_.get_service().send_to(this->impl_.get_implementation(),
buffers, destination, flags, ec);
}

@@ -494,9 +608,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@@ -517,13 +631,10 @@ public:
const endpoint_type& destination,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send_to(
this->get_implementation(), buffers, destination, 0,
ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send_to(), handler, this, buffers,
destination, socket_base::message_flags(0));
}

/// Start an asynchronous send.
@@ -549,9 +660,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
@@ -560,13 +671,9 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send_to(
this->get_implementation(), buffers, destination, flags,
ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send_to(), handler, this, buffers, destination, flags);
}

/// Receive some data on a connected socket.
@@ -597,8 +704,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -626,8 +733,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -654,8 +761,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous receive on a connected socket.
@@ -676,9 +783,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@@ -700,12 +807,10 @@ public:
async_receive(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous receive on a connected socket.
@@ -728,9 +833,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@@ -743,12 +848,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this, buffers, flags);
}

/// Receive a datagram with the endpoint of the sender.
@@ -782,8 +884,8 @@ public:
endpoint_type& sender_endpoint)
{
asio::error_code ec;
std::size_t s = this->get_service().receive_from(
this->get_implementation(), buffers, sender_endpoint, 0, ec);
std::size_t s = this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);
asio::detail::throw_error(ec, "receive_from");
return s;
}
@@ -809,8 +911,8 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive_from(
this->get_implementation(), buffers, sender_endpoint, flags, ec);
std::size_t s = this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
asio::detail::throw_error(ec, "receive_from");
return s;
}
@@ -836,8 +938,8 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->get_service().receive_from(this->get_implementation(),
buffers, sender_endpoint, flags, ec);
return this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
}

/// Start an asynchronous receive.
@@ -863,9 +965,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@@ -883,13 +985,10 @@ public:
endpoint_type& sender_endpoint,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive_from(
this->get_implementation(), buffers, sender_endpoint, 0,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_from(), handler, this, buffers,
&sender_endpoint, socket_base::message_flags(0));
}

/// Start an asynchronous receive.
@@ -917,9 +1016,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
@@ -928,14 +1027,85 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive_from(
this->get_implementation(), buffers, sender_endpoint, flags,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_from(), handler,
this, buffers, &sender_endpoint, flags);
}

private:
struct initiate_async_send
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_datagram_socket* self, const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_send_to
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_datagram_socket* self, const ConstBufferSequence& buffers,
const endpoint_type& destination,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send_to(
self->impl_.get_implementation(), buffers, destination, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_datagram_socket* self, const MutableBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive_from
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_datagram_socket* self, const MutableBufferSequence& buffers,
endpoint_type* sender_endpoint, socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive_from(
self->impl_.get_implementation(), buffers, *sender_endpoint, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};
};

} // namespace asio


+ 194
- 49
source/modules/hylia/link/asio/basic_deadline_timer.hpp View File

@@ -2,7 +2,7 @@
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -21,11 +21,15 @@
|| defined(GENERATING_DOCUMENTATION)

#include <cstddef>
#include "asio/basic_io_object.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/time_traits.hpp"

#include "asio/detail/push_options.hpp"

@@ -50,7 +54,7 @@ namespace asio {
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(io_context);
* asio::deadline_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
@@ -73,7 +77,7 @@ namespace asio {
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(io_context,
* asio::deadline_timer timer(my_context,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
@@ -121,11 +125,13 @@ namespace asio {
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time>,
typename TimerService = deadline_timer_service<Time, TimeTraits> >
typename Executor = executor>
class basic_deadline_timer
: public basic_io_object<TimerService>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// The time traits type.
typedef TimeTraits traits_type;

@@ -141,11 +147,30 @@ public:
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(asio::io_context& io_context)
: basic_io_object<TimerService>(io_context)
explicit basic_deadline_timer(const executor_type& ex)
: impl_(ex)
{
}

/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_deadline_timer(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}

@@ -153,18 +178,40 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(asio::io_context& io_context,
const time_type& expiry_time)
: basic_io_object<TimerService>(io_context)
basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
: impl_(ex)
{
asio::error_code ec;
this->get_service().expires_at(this->get_implementation(), expiry_time, ec);
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}

/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}

@@ -172,22 +219,98 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(asio::io_context& io_context,
basic_deadline_timer(const executor_type& ex,
const duration_type& expiry_time)
: basic_io_object<TimerService>(io_context)
: impl_(ex)
{
asio::error_code ec;
this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}

/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context,
const duration_type& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}

#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_deadline_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer(basic_deadline_timer&& other)
: impl_(std::move(other.impl_))
{
}

/// Move-assign a basic_deadline_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer& operator=(basic_deadline_timer&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_deadline_timer()
{
}

/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}

/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
@@ -213,7 +336,7 @@ public:
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel(this->get_implementation(), ec);
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
return s;
}
@@ -242,7 +365,7 @@ public:
*/
std::size_t cancel(asio::error_code& ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}

/// Cancels one asynchronous operation that is waiting on the timer.
@@ -272,8 +395,8 @@ public:
std::size_t cancel_one()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel_one(
this->get_implementation(), ec);
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one");
return s;
}
@@ -304,7 +427,7 @@ public:
*/
std::size_t cancel_one(asio::error_code& ec)
{
return this->get_service().cancel_one(this->get_implementation(), ec);
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}

/// Get the timer's expiry time as an absolute time.
@@ -314,7 +437,7 @@ public:
*/
time_type expires_at() const
{
return this->get_service().expires_at(this->get_implementation());
return impl_.get_service().expires_at(impl_.get_implementation());
}

/// Set the timer's expiry time as an absolute time.
@@ -342,8 +465,8 @@ public:
std::size_t expires_at(const time_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
return s;
}
@@ -373,8 +496,8 @@ public:
std::size_t expires_at(const time_type& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}

/// Get the timer's expiry time relative to now.
@@ -384,7 +507,7 @@ public:
*/
duration_type expires_from_now() const
{
return this->get_service().expires_from_now(this->get_implementation());
return impl_.get_service().expires_from_now(impl_.get_implementation());
}

/// Set the timer's expiry time relative to now.
@@ -412,8 +535,8 @@ public:
std::size_t expires_from_now(const duration_type& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
return s;
}
@@ -443,8 +566,8 @@ public:
std::size_t expires_from_now(const duration_type& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}

/// Perform a blocking wait on the timer.
@@ -457,7 +580,7 @@ public:
void wait()
{
asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec);
impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}

@@ -470,7 +593,7 @@ public:
*/
void wait(asio::error_code& ec)
{
this->get_service().wait(this->get_implementation(), ec);
impl_.get_service().wait(impl_.get_implementation(), ec);
}

/// Start an asynchronous wait on the timer.
@@ -493,22 +616,44 @@ public:
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(ASIO_MOVE_ARG(WaitHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;

return this->get_service().async_wait(this->get_implementation(),
ASIO_MOVE_CAST(WaitHandler)(handler));
return async_initiate<WaitHandler, void (asio::error_code)>(
initiate_async_wait(), handler, this);
}

private:
// Disallow copying and assignment.
basic_deadline_timer(const basic_deadline_timer&) ASIO_DELETED;
basic_deadline_timer& operator=(
const basic_deadline_timer&) ASIO_DELETED;

struct initiate_async_wait
{
template <typename WaitHandler>
void operator()(ASIO_MOVE_ARG(WaitHandler) handler,
basic_deadline_timer* self) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;

detail::non_const_lvalue<WaitHandler> handler2(handler);
self->impl_.get_service().async_wait(
self->impl_.get_implementation(), handler2.value,
self->impl_.get_implementation_executor());
}
};

detail::io_object_impl<
detail::deadline_timer_service<TimeTraits>, Executor> impl_;
};

} // namespace asio


+ 20
- 4
source/modules/hylia/link/asio/basic_io_object.hpp View File

@@ -2,7 +2,7 @@
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -34,12 +34,13 @@ namespace detail
typedef typename service_type::implementation_type implementation_type;

template <typename T, typename U>
static auto eval(T* t, U* u) -> decltype(t->move_construct(*u, *u), char());
static char (&eval(...))[2];
static auto asio_service_has_move_eval(T* t, U* u)
-> decltype(t->move_construct(*u, *u), char());
static char (&asio_service_has_move_eval(...))[2];

public:
static const bool value =
sizeof(service_has_move::eval(
sizeof(asio_service_has_move_eval(
static_cast<service_type*>(0),
static_cast<implementation_type*>(0))) == 1;
};
@@ -137,6 +138,11 @@ protected:
* @note Available only for services that support movability,
*/
basic_io_object& operator=(basic_io_object&& other);

/// Perform a converting move-construction of a basic_io_object.
template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation);
#endif // defined(GENERATING_DOCUMENTATION)

/// Protected destructor to prevent deletion through this type.
@@ -225,6 +231,16 @@ protected:
service_->move_construct(implementation_, other.implementation_);
}

template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation)
: service_(&asio::use_service<IoObjectService>(
other_service.get_io_context()))
{
service_->converting_move_construct(implementation_,
other_service, other_implementation);
}

~basic_io_object()
{
service_->destroy(implementation_);


+ 322
- 151
source/modules/hylia/link/asio/basic_raw_socket.hpp View File

@@ -2,7 +2,7 @@
// basic_raw_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -19,15 +19,24 @@
#include <cstddef>
#include "asio/basic_socket.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/raw_socket_service.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {

#if !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)
#define ASIO_BASIC_RAW_SOCKET_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_raw_socket;

#endif // !defined(ASIO_BASIC_RAW_SOCKET_FWD_DECL)

/// Provides raw-oriented socket functionality.
/**
* The basic_raw_socket class template provides asynchronous and blocking
@@ -37,14 +46,29 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename RawSocketService = raw_socket_service<Protocol> >
template <typename Protocol, typename Executor>
class basic_raw_socket
: public basic_socket<Protocol, RawSocketService>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_raw_socket<Protocol, Executor1> other;
};

/// The native representation of a socket.
typedef typename RawSocketService::native_handle_type native_handle_type;
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif

/// The protocol type.
typedef Protocol protocol_type;
@@ -57,12 +81,29 @@ public:
* This constructor creates a raw socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_raw_socket(asio::io_context& io_context)
: basic_socket<Protocol, RawSocketService>(io_context)
explicit basic_raw_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}

/// Construct a basic_raw_socket without opening it.
/**
* This constructor creates a raw socket without opening it. The open()
* function must be called before data can be sent or received on the socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_raw_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}

@@ -70,17 +111,36 @@ public:
/**
* This constructor creates and opens a raw socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol, RawSocketService>(io_context, protocol)
basic_raw_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}

/// Construct and open a basic_raw_socket.
/**
* This constructor creates and opens a raw socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context, const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}

@@ -91,18 +151,41 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the raw
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol, RawSocketService>(io_context, endpoint)
basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}

/// Construct a basic_raw_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a raw socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the raw
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}

@@ -111,9 +194,8 @@ public:
* This constructor creates a raw socket object to hold an existing
* native socket.
*
* @param io_context The io_context object that the raw socket will use
* to dispatch handlers for any asynchronous operations performed on the
* socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@@ -121,10 +203,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_raw_socket(asio::io_context& io_context,
basic_raw_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, RawSocketService>(
io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}

/// Construct a basic_raw_socket on an existing native socket.
/**
* This constructor creates a raw socket object to hold an existing
* native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_raw_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}

@@ -137,11 +243,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
basic_raw_socket(basic_raw_socket&& other)
: basic_socket<Protocol, RawSocketService>(
ASIO_MOVE_CAST(basic_raw_socket)(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -153,31 +259,34 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
basic_raw_socket& operator=(basic_raw_socket&& other)
{
basic_socket<Protocol, RawSocketService>::operator=(
ASIO_MOVE_CAST(basic_raw_socket)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}

/// Move-construct a basic_raw_socket from a socket of another protocol type.
/// Move-construct a basic_raw_socket from a socket of another protocol
/// type.
/**
* This constructor moves a raw socket from one object to another.
*
* @param other The other basic_raw_socket object from which the move will
* occur.
* @param other The other basic_raw_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename RawSocketService1>
basic_raw_socket(basic_raw_socket<Protocol1, RawSocketService1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol, RawSocketService>(
ASIO_MOVE_CAST2(basic_raw_socket<
Protocol1, RawSocketService1>)(other))
template <typename Protocol1, typename Executor1>
basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -189,20 +298,30 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_raw_socket(io_context&) constructor.
* constructed using the @c basic_raw_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename RawSocketService1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_raw_socket>::type& operator=(
basic_raw_socket<Protocol1, RawSocketService1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_raw_socket&
>::type operator=(basic_raw_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, RawSocketService>::operator=(
ASIO_MOVE_CAST2(basic_raw_socket<
Protocol1, RawSocketService1>)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_raw_socket()
{
}

/// Send some data on a connected socket.
/**
* This function is used to send data on the raw socket. The function call
@@ -228,8 +347,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -255,8 +374,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -281,8 +400,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().send(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous send on a connected socket.
@@ -303,9 +422,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected raw
@@ -326,12 +445,10 @@ public:
async_send(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous send on a connected socket.
@@ -354,9 +471,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_send operation can only be used with a connected socket.
* Use the async_send_to function to send data on an unconnected raw
@@ -369,12 +486,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this, buffers, flags);
}

/// Send raw data to the specified endpoint.
@@ -407,8 +521,8 @@ public:
const endpoint_type& destination)
{
asio::error_code ec;
std::size_t s = this->get_service().send_to(
this->get_implementation(), buffers, destination, 0, ec);
std::size_t s = this->impl_.get_service().send_to(
this->impl_.get_implementation(), buffers, destination, 0, ec);
asio::detail::throw_error(ec, "send_to");
return s;
}
@@ -434,8 +548,8 @@ public:
const endpoint_type& destination, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send_to(
this->get_implementation(), buffers, destination, flags, ec);
std::size_t s = this->impl_.get_service().send_to(
this->impl_.get_implementation(), buffers, destination, flags, ec);
asio::detail::throw_error(ec, "send_to");
return s;
}
@@ -461,7 +575,7 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->get_service().send_to(this->get_implementation(),
return this->impl_.get_service().send_to(this->impl_.get_implementation(),
buffers, destination, flags, ec);
}

@@ -486,9 +600,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@@ -509,12 +623,10 @@ public:
const endpoint_type& destination,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send_to(this->get_implementation(),
buffers, destination, 0, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send_to(), handler, this, buffers,
destination, socket_base::message_flags(0));
}

/// Start an asynchronous send.
@@ -540,9 +652,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
@@ -551,13 +663,9 @@ public:
const endpoint_type& destination, socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send_to(
this->get_implementation(), buffers, destination, flags,
ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send_to(), handler, this, buffers, destination, flags);
}

/// Receive some data on a connected socket.
@@ -588,8 +696,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -617,8 +725,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -645,8 +753,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous receive on a connected socket.
@@ -667,9 +775,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@@ -691,12 +799,10 @@ public:
async_receive(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous receive on a connected socket.
@@ -719,9 +825,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The async_receive operation can only be used with a connected socket.
* Use the async_receive_from function to receive data on an unconnected
@@ -734,12 +840,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this, buffers, flags);
}

/// Receive raw data with the endpoint of the sender.
@@ -773,8 +876,8 @@ public:
endpoint_type& sender_endpoint)
{
asio::error_code ec;
std::size_t s = this->get_service().receive_from(
this->get_implementation(), buffers, sender_endpoint, 0, ec);
std::size_t s = this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec);
asio::detail::throw_error(ec, "receive_from");
return s;
}
@@ -800,8 +903,8 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive_from(
this->get_implementation(), buffers, sender_endpoint, flags, ec);
std::size_t s = this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
asio::detail::throw_error(ec, "receive_from");
return s;
}
@@ -827,8 +930,8 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
asio::error_code& ec)
{
return this->get_service().receive_from(this->get_implementation(),
buffers, sender_endpoint, flags, ec);
return this->impl_.get_service().receive_from(
this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec);
}

/// Start an asynchronous receive.
@@ -854,9 +957,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@@ -874,13 +977,10 @@ public:
endpoint_type& sender_endpoint,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive_from(
this->get_implementation(), buffers, sender_endpoint, 0,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_from(), handler, this, buffers,
&sender_endpoint, socket_base::message_flags(0));
}

/// Start an asynchronous receive.
@@ -908,9 +1008,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
@@ -919,14 +1019,85 @@ public:
endpoint_type& sender_endpoint, socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive_from(
this->get_implementation(), buffers, sender_endpoint, flags,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_from(), handler,
this, buffers, &sender_endpoint, flags);
}

private:
struct initiate_async_send
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_raw_socket* self, const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_send_to
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_raw_socket* self, const ConstBufferSequence& buffers,
const endpoint_type& destination,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send_to(
self->impl_.get_implementation(), buffers, destination, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_raw_socket* self, const MutableBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive_from
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_raw_socket* self, const MutableBufferSequence& buffers,
endpoint_type* sender_endpoint, socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive_from(
self->impl_.get_implementation(), buffers, *sender_endpoint, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};
};

} // namespace asio


+ 240
- 89
source/modules/hylia/link/asio/basic_seq_packet_socket.hpp View File

@@ -2,7 +2,7 @@
// basic_seq_packet_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -21,12 +21,20 @@
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/seq_packet_socket_service.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {

#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_seq_packet_socket;

#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)

/// Provides sequenced packet socket functionality.
/**
* The basic_seq_packet_socket class template provides asynchronous and blocking
@@ -36,15 +44,29 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Protocol,
typename SeqPacketSocketService = seq_packet_socket_service<Protocol> >
template <typename Protocol, typename Executor>
class basic_seq_packet_socket
: public basic_socket<Protocol, SeqPacketSocketService>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_seq_packet_socket<Protocol, Executor1> other;
};

/// The native representation of a socket.
typedef typename SeqPacketSocketService::native_handle_type
native_handle_type;
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif

/// The protocol type.
typedef Protocol protocol_type;
@@ -58,12 +80,30 @@ public:
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_seq_packet_socket(asio::io_context& io_context)
: basic_socket<Protocol, SeqPacketSocketService>(io_context)
explicit basic_seq_packet_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}

/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_seq_packet_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}

@@ -73,17 +113,40 @@ public:
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol)
: basic_socket<Protocol, SeqPacketSocketService>(io_context, protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}

/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}

@@ -94,18 +157,43 @@ public:
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const endpoint_type& endpoint)
: basic_socket<Protocol, SeqPacketSocketService>(io_context, endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}

/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}

@@ -114,9 +202,8 @@ public:
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param io_context The io_context object that the sequenced packet socket
* will use to dispatch handlers for any asynchronous operations performed on
* the socket.
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
@@ -124,10 +211,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(asio::io_context& io_context,
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, SeqPacketSocketService>(
io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}

/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}

@@ -141,11 +252,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket(basic_seq_packet_socket&& other)
: basic_socket<Protocol, SeqPacketSocketService>(
ASIO_MOVE_CAST(basic_seq_packet_socket)(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -158,12 +269,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
{
basic_socket<Protocol, SeqPacketSocketService>::operator=(
ASIO_MOVE_CAST(basic_seq_packet_socket)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}

@@ -177,15 +288,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename SeqPacketSocketService1>
basic_seq_packet_socket(
basic_seq_packet_socket<Protocol1, SeqPacketSocketService1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol, SeqPacketSocketService>(
ASIO_MOVE_CAST2(basic_seq_packet_socket<
Protocol1, SeqPacketSocketService1>)(other))
template <typename Protocol1, typename Executor1>
basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -199,20 +311,30 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(io_context&) constructor.
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename SeqPacketSocketService1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_seq_packet_socket>::type& operator=(
basic_seq_packet_socket<Protocol1, SeqPacketSocketService1>&& other)
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_seq_packet_socket&
>::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, SeqPacketSocketService>::operator=(
ASIO_MOVE_CAST2(basic_seq_packet_socket<
Protocol1, SeqPacketSocketService1>)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_seq_packet_socket()
{
}

/// Send some data on the socket.
/**
* This function is used to send data on the sequenced packet socket. The
@@ -241,8 +363,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -269,8 +391,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().send(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous send.
@@ -293,9 +415,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
@@ -313,12 +435,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this, buffers, flags);
}

/// Receive some data on the socket.
@@ -355,8 +474,8 @@ public:
socket_base::message_flags& out_flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, 0, out_flags, ec);
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, 0, out_flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -402,8 +521,8 @@ public:
socket_base::message_flags& out_flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, in_flags, out_flags, ec);
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -436,8 +555,8 @@ public:
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, asio::error_code& ec)
{
return this->get_service().receive(this->get_implementation(),
buffers, in_flags, out_flags, ec);
return this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
}

/// Start an asynchronous receive.
@@ -464,9 +583,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@@ -485,13 +604,10 @@ public:
socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(
this->get_implementation(), buffers, 0, out_flags,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_with_flags(), handler, this,
buffers, socket_base::message_flags(0), &out_flags);
}

/// Start an asynchronous receive.
@@ -520,9 +636,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
@@ -544,14 +660,49 @@ public:
socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(
this->get_implementation(), buffers, in_flags, out_flags,
ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive_with_flags(), handler,
this, buffers, in_flags, &out_flags);
}

private:
struct initiate_async_send
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_seq_packet_socket* self, const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive_with_flags
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_seq_packet_socket* self, const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags* out_flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive_with_flags(
self->impl_.get_implementation(), buffers, in_flags, *out_flags,
handler2.value, self->impl_.get_implementation_executor());
}
};
};

} // namespace asio


+ 273
- 93
source/modules/hylia/link/asio/basic_serial_port.hpp View File

@@ -2,7 +2,7 @@
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
@@ -22,12 +22,25 @@
|| defined(GENERATING_DOCUMENTATION)

#include <string>
#include "asio/basic_io_object.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/serial_port_service.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_serial_port_service.hpp"
#else
# include "asio/detail/reactive_serial_port_service.hpp"
#endif

#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)

#include "asio/detail/push_options.hpp"

@@ -35,35 +48,84 @@ namespace asio {

/// Provides serial port functionality.
/**
* The basic_serial_port class template provides functionality that is common
* to all serial ports.
* The basic_serial_port class provides a wrapper over serial port
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename SerialPortService = serial_port_service>
template <typename Executor = executor>
class basic_serial_port
: public basic_io_object<SerialPortService>,
public serial_port_base
: public serial_port_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// The native representation of a serial port.
typedef typename SerialPortService::native_handle_type native_handle_type;
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_serial_port_service::native_handle_type
native_handle_type;
#endif

/// A basic_basic_serial_port is always the lowest layer.
typedef basic_serial_port lowest_layer_type;

/// A basic_serial_port is always the lowest layer.
typedef basic_serial_port<SerialPortService> lowest_layer_type;
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*/
explicit basic_serial_port(const executor_type& ex)
: impl_(ex)
{
}

/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param io_context The io_context object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*/
template <typename ExecutionContext>
explicit basic_serial_port(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value,
basic_serial_port
>::type* = 0)
: impl_(context)
{
}

/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
explicit basic_serial_port(asio::io_context& io_context)
: basic_io_object<SerialPortService>(io_context)
basic_serial_port(const executor_type& ex, const char* device)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}

/// Construct and open a basic_serial_port.
@@ -71,18 +133,22 @@ public:
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param io_context The io_context object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
explicit basic_serial_port(asio::io_context& io_context,
const char* device)
: basic_io_object<SerialPortService>(io_context)
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const char* device,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec);
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}

@@ -91,18 +157,42 @@ public:
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param io_context The io_context object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
explicit basic_serial_port(asio::io_context& io_context,
const std::string& device)
: basic_io_object<SerialPortService>(io_context)
basic_serial_port(const executor_type& ex, const std::string& device)
: impl_(ex)
{
asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec);
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}

/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const std::string& device,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}

@@ -111,19 +201,47 @@ public:
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param io_context The io_context object that the serial port will use to
* dispatch handlers for any asynchronous operations performed on the port.
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
basic_serial_port(asio::io_context& io_context,
basic_serial_port(const executor_type& ex,
const native_handle_type& native_serial_port)
: basic_io_object<SerialPortService>(io_context)
: impl_(ex)
{
asio::error_code ec;
this->get_service().assign(this->get_implementation(),
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}

/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context,
const native_handle_type& native_serial_port,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
@@ -137,11 +255,11 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(io_context&) constructor.
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port(basic_serial_port&& other)
: basic_io_object<SerialPortService>(
ASIO_MOVE_CAST(basic_serial_port)(other))
: impl_(std::move(other.impl_))
{
}

@@ -153,16 +271,32 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(io_context&) constructor.
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port& operator=(basic_serial_port&& other)
{
basic_io_object<SerialPortService>::operator=(
ASIO_MOVE_CAST(basic_serial_port)(other));
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the serial port.
/**
* This function destroys the serial port, cancelling any outstanding
* asynchronous wait operations associated with the serial port as if by
* calling @c cancel.
*/
~basic_serial_port()
{
}

/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}

/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
@@ -202,7 +336,7 @@ public:
void open(const std::string& device)
{
asio::error_code ec;
this->get_service().open(this->get_implementation(), device, ec);
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}

@@ -215,10 +349,11 @@ public:
*
* @param ec Set the indicate what error occurred, if any.
*/
asio::error_code open(const std::string& device,
ASIO_SYNC_OP_VOID open(const std::string& device,
asio::error_code& ec)
{
return this->get_service().open(this->get_implementation(), device, ec);
impl_.get_service().open(impl_.get_implementation(), device, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Assign an existing native serial port to the serial port.
@@ -232,7 +367,7 @@ public:
void assign(const native_handle_type& native_serial_port)
{
asio::error_code ec;
this->get_service().assign(this->get_implementation(),
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
@@ -245,17 +380,18 @@ public:
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code assign(const native_handle_type& native_serial_port,
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
asio::error_code& ec)
{
return this->get_service().assign(this->get_implementation(),
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Determine whether the serial port is open.
bool is_open() const
{
return this->get_service().is_open(this->get_implementation());
return impl_.get_service().is_open(impl_.get_implementation());
}

/// Close the serial port.
@@ -269,7 +405,7 @@ public:
void close()
{
asio::error_code ec;
this->get_service().close(this->get_implementation(), ec);
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}

@@ -281,9 +417,10 @@ public:
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code close(asio::error_code& ec)
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
return this->get_service().close(this->get_implementation(), ec);
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Get the native serial port representation.
@@ -294,7 +431,7 @@ public:
*/
native_handle_type native_handle()
{
return this->get_service().native_handle(this->get_implementation());
return impl_.get_service().native_handle(impl_.get_implementation());
}

/// Cancel all asynchronous operations associated with the serial port.
@@ -308,7 +445,7 @@ public:
void cancel()
{
asio::error_code ec;
this->get_service().cancel(this->get_implementation(), ec);
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}

@@ -320,9 +457,10 @@ public:
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code cancel(asio::error_code& ec)
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Send a break sequence to the serial port.
@@ -335,7 +473,7 @@ public:
void send_break()
{
asio::error_code ec;
this->get_service().send_break(this->get_implementation(), ec);
impl_.get_service().send_break(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "send_break");
}

@@ -346,9 +484,10 @@ public:
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code send_break(asio::error_code& ec)
ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)
{
return this->get_service().send_break(this->get_implementation(), ec);
impl_.get_service().send_break(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Set an option on the serial port.
@@ -370,7 +509,7 @@ public:
void set_option(const SettableSerialPortOption& option)
{
asio::error_code ec;
this->get_service().set_option(this->get_implementation(), option, ec);
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "set_option");
}

@@ -390,11 +529,11 @@ public:
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
asio::error_code set_option(const SettableSerialPortOption& option,
ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
asio::error_code& ec)
{
return this->get_service().set_option(
this->get_implementation(), option, ec);
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Get an option from the serial port.
@@ -417,7 +556,7 @@ public:
void get_option(GettableSerialPortOption& option)
{
asio::error_code ec;
this->get_service().get_option(this->get_implementation(), option, ec);
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "get_option");
}

@@ -438,11 +577,11 @@ public:
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
asio::error_code get_option(GettableSerialPortOption& option,
ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
asio::error_code& ec)
{
return this->get_service().get_option(
this->get_implementation(), option, ec);
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Write some data to the serial port.
@@ -466,7 +605,7 @@ public:
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* serial_port.write_some(asio::buffer(data, size));
* basic_serial_port.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
@@ -476,8 +615,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().write_some(
this->get_implementation(), buffers, ec);
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
@@ -502,8 +641,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->get_service().write_some(
this->get_implementation(), buffers, ec);
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}

/// Start an asynchronous write.
@@ -524,9 +663,9 @@ public:
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@@ -535,7 +674,8 @@ public:
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* serial_port.async_write_some(asio::buffer(data, size), handler);
* basic_serial_port.async_write_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
@@ -547,12 +687,9 @@ public:
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_write_some(this->get_implementation(),
buffers, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(), handler, this, buffers);
}

/// Read some data from the serial port.
@@ -577,7 +714,7 @@ public:
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* serial_port.read_some(asio::buffer(data, size));
* basic_serial_port.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
@@ -587,8 +724,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().read_some(
this->get_implementation(), buffers, ec);
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
@@ -614,8 +751,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->get_service().read_some(
this->get_implementation(), buffers, ec);
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}

/// Start an asynchronous read.
@@ -636,9 +773,9 @@ public:
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
@@ -648,7 +785,8 @@ public:
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* serial_port.async_read_some(asio::buffer(data, size), handler);
* basic_serial_port.async_read_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
@@ -660,13 +798,55 @@ public:
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_read_some(this->get_implementation(),
buffers, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(), handler, this, buffers);
}

private:
// Disallow copying and assignment.
basic_serial_port(const basic_serial_port&) ASIO_DELETED;
basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED;

struct initiate_async_write_some
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_serial_port* self, const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_write_some(
self->impl_.get_implementation(), buffers, handler2.value,
self->impl_.get_implementation_executor());
}
};

struct initiate_async_read_some
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_serial_port* self, const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_read_some(
self->impl_.get_implementation(), buffers, handler2.value,
self->impl_.get_implementation_executor());
}
};

#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_serial_port_service, Executor> impl_;
#endif
};

} // namespace asio


+ 217
- 62
source/modules/hylia/link/asio/basic_signal_set.hpp View File

@@ -2,7 +2,7 @@
// basic_signal_set.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -17,22 +17,23 @@

#include "asio/detail/config.hpp"

#include "asio/basic_io_object.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/signal_set_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/signal_set_service.hpp"

#include "asio/detail/push_options.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"

namespace asio {

/// Provides signal functionality.
/**
* The basic_signal_set class template provides the ability to perform an
* asynchronous wait for one or more signals to occur.
*
* Most applications will use the asio::signal_set typedef.
* The basic_signal_set class provides the ability to perform an asynchronous
* wait for one or more signals to occur.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
@@ -54,7 +55,7 @@ namespace asio {
* ...
*
* // Construct a signal set registered for process termination.
* asio::signal_set signals(io_context, SIGINT, SIGTERM);
* asio::signal_set signals(my_context, SIGINT, SIGTERM);
*
* // Start an asynchronous wait for one of the signals to occur.
* signals.async_wait(handler);
@@ -89,41 +90,88 @@ namespace asio {
* that any signals registered using signal_set objects are unblocked in at
* least one thread.
*/
template <typename SignalSetService = signal_set_service>
template <typename Executor = executor>
class basic_signal_set
: public basic_io_object<SignalSetService>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*/
explicit basic_signal_set(const executor_type& ex)
: impl_(ex)
{
}

/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param io_context The io_context object that the signal set will use to
* dispatch handlers for any asynchronous operations performed on the set.
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*/
template <typename ExecutionContext>
explicit basic_signal_set(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}

/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1); @endcode
*/
explicit basic_signal_set(asio::io_context& io_context)
: basic_io_object<SignalSetService>(io_context)
basic_signal_set(const executor_type& ex, int signal_number_1)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}

/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param io_context The io_context object that the signal set will use to
* dispatch handlers for any asynchronous operations performed on the set.
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context);
* @code asio::signal_set signals(context);
* signals.add(signal_number_1); @endcode
*/
basic_signal_set(asio::io_context& io_context, int signal_number_1)
: basic_io_object<SignalSetService>(io_context)
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}

@@ -131,26 +179,59 @@ public:
/**
* This constructor creates a signal set and registers for two signals.
*
* @param io_context The io_context object that the signal set will use to
* dispatch handlers for any asynchronous operations performed on the set.
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context);
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
basic_signal_set(asio::io_context& io_context, int signal_number_1,
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2)
: basic_io_object<SignalSetService>(io_context)
: impl_(ex)
{
asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_2, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}

/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}

@@ -158,8 +239,9 @@ public:
/**
* This constructor creates a signal set and registers for three signals.
*
* @param io_context The io_context object that the signal set will use to
* dispatch handlers for any asynchronous operations performed on the set.
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
@@ -168,24 +250,77 @@ public:
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(io_context);
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
basic_signal_set(asio::io_context& io_context, int signal_number_1,
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2, int signal_number_3)
: basic_io_object<SignalSetService>(io_context)
: impl_(ex)
{
asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number_1, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_2, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
this->get_service().add(this->get_implementation(), signal_number_3, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}

/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2, int signal_number_3,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}

/// Destroys the signal set.
/**
* This function destroys the signal set, cancelling any outstanding
* asynchronous wait operations associated with the signal set as if by
* calling @c cancel.
*/
~basic_signal_set()
{
}

/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}

/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
@@ -198,7 +333,7 @@ public:
void add(int signal_number)
{
asio::error_code ec;
this->get_service().add(this->get_implementation(), signal_number, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "add");
}

@@ -211,11 +346,11 @@ public:
*
* @param ec Set to indicate what error occurred, if any.
*/
asio::error_code add(int signal_number,
ASIO_SYNC_OP_VOID add(int signal_number,
asio::error_code& ec)
{
return this->get_service().add(
this->get_implementation(), signal_number, ec);
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Remove a signal from a signal_set.
@@ -233,7 +368,7 @@ public:
void remove(int signal_number)
{
asio::error_code ec;
this->get_service().remove(this->get_implementation(), signal_number, ec);
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "remove");
}

@@ -249,11 +384,11 @@ public:
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
asio::error_code remove(int signal_number,
ASIO_SYNC_OP_VOID remove(int signal_number,
asio::error_code& ec)
{
return this->get_service().remove(
this->get_implementation(), signal_number, ec);
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Remove all signals from a signal_set.
@@ -268,7 +403,7 @@ public:
void clear()
{
asio::error_code ec;
this->get_service().clear(this->get_implementation(), ec);
impl_.get_service().clear(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "clear");
}

@@ -281,9 +416,10 @@ public:
*
* @note Removes all queued notifications.
*/
asio::error_code clear(asio::error_code& ec)
ASIO_SYNC_OP_VOID clear(asio::error_code& ec)
{
return this->get_service().clear(this->get_implementation(), ec);
impl_.get_service().clear(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Cancel all operations associated with the signal set.
@@ -310,7 +446,7 @@ public:
void cancel()
{
asio::error_code ec;
this->get_service().cancel(this->get_implementation(), ec);
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}

@@ -335,9 +471,10 @@ public:
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
asio::error_code cancel(asio::error_code& ec)
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Start an asynchronous operation to wait for a signal to be delivered.
@@ -361,26 +498,44 @@ public:
* int signal_number // Indicates which signal occurred.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename SignalHandler>
ASIO_INITFN_RESULT_TYPE(SignalHandler,
void (asio::error_code, int))
async_wait(ASIO_MOVE_ARG(SignalHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a SignalHandler.
ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;

return this->get_service().async_wait(this->get_implementation(),
ASIO_MOVE_CAST(SignalHandler)(handler));
return async_initiate<SignalHandler, void (asio::error_code, int)>(
initiate_async_wait(), handler, this);
}

private:
// Disallow copying and assignment.
basic_signal_set(const basic_signal_set&) ASIO_DELETED;
basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED;

struct initiate_async_wait
{
template <typename SignalHandler>
void operator()(ASIO_MOVE_ARG(SignalHandler) handler,
basic_signal_set* self) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a SignalHandler.
ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;

detail::non_const_lvalue<SignalHandler> handler2(handler);
self->impl_.get_service().async_wait(
self->impl_.get_implementation(), handler2.value,
self->impl_.get_implementation_executor());
}
};

detail::io_object_impl<detail::signal_set_service, Executor> impl_;
};

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_BASIC_SIGNAL_SET_HPP

+ 426
- 169
source/modules/hylia/link/asio/basic_socket.hpp
File diff suppressed because it is too large
View File


+ 934
- 290
source/modules/hylia/link/asio/basic_socket_acceptor.hpp
File diff suppressed because it is too large
View File


+ 127
- 45
source/modules/hylia/link/asio/basic_socket_iostream.hpp View File

@@ -2,7 +2,7 @@
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -22,7 +22,6 @@
#include <istream>
#include <ostream>
#include "asio/basic_socket_streambuf.hpp"
#include "asio/stream_socket_service.hpp"

#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)

@@ -33,8 +32,7 @@
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : std::basic_iostream<char>(
// &this->detail::socket_iostream_base<
// Protocol, StreamSocketService, Time,
// TimeTraits, TimerService>::streambuf_)
// Protocol, Clock, WaitTraits>::streambuf_)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
@@ -46,8 +44,7 @@
explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
: std::basic_iostream<char>( \
&this->detail::socket_iostream_base< \
Protocol, StreamSocketService, Time, \
TimeTraits, TimerService>::streambuf_) \
Protocol, Clock, WaitTraits>::streambuf_) \
{ \
this->setf(std::ios_base::unitbuf); \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
@@ -82,60 +79,102 @@ namespace detail {

// A separate base class is used to ensure that the streambuf is initialised
// prior to the basic_socket_iostream's basic_iostream base class.
template <typename Protocol, typename StreamSocketService,
typename Time, typename TimeTraits, typename TimerService>
template <typename Protocol, typename Clock, typename WaitTraits>
class socket_iostream_base
{
protected:
basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService> streambuf_;
socket_iostream_base()
{
}

#if defined(ASIO_HAS_MOVE)
socket_iostream_base(socket_iostream_base&& other)
: streambuf_(std::move(other.streambuf_))
{
}

socket_iostream_base(basic_stream_socket<Protocol> s)
: streambuf_(std::move(s))
{
}

socket_iostream_base& operator=(socket_iostream_base&& other)
{
streambuf_ = std::move(other.streambuf_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE)

basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;
};

}
} // namespace detail

/// Iostream interface for a socket.
#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol>,
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
typename Time = boost::posix_time::ptime,
typename TimeTraits = asio::time_traits<Time>,
typename TimerService = deadline_timer_service<Time, TimeTraits> >
#else
typename Time = steady_timer::clock_type,
typename TimeTraits = steady_timer::traits_type,
typename TimerService = steady_timer::service_type>
#endif
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> >
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_iostream;

#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)

/// Iostream interface for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_iostream
: private detail::socket_iostream_base<Protocol,
StreamSocketService, Time, TimeTraits, TimerService>,
: private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,
public std::basic_iostream<char>
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME)
typedef TimeTraits traits_helper;
#else
typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
#endif
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)

public:
/// The protocol type.
typedef Protocol protocol_type;

/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;

/// The clock type.
typedef Clock clock_type;

#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename TimeTraits::time_type time_type;
typedef typename WaitTraits::time_type time_type;

/// The time type.
typedef typename TimeTraits::time_point time_point;
typedef typename WaitTraits::time_point time_point;

/// (Deprecated: Use duration.) The duration type.
typedef typename TimeTraits::duration_type duration_type;
typedef typename WaitTraits::duration_type duration_type;

/// The duration type.
typedef typename TimeTraits::duration duration;
typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
@@ -149,12 +188,47 @@ public:
basic_socket_iostream()
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, StreamSocketService, Time,
TimeTraits, TimerService>::streambuf_)
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}

#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_iostream from the supplied socket.
explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(s)),
std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}

#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \
|| defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_socket_iostream from another.
basic_socket_iostream(basic_socket_iostream&& other)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(other)),
std::basic_iostream<char>(std::move(other))
{
this->set_rdbuf(&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_);
}

/// Move-assign a basic_socket_iostream from another.
basic_socket_iostream& operator=(basic_socket_iostream&& other)
{
std::basic_iostream<char>::operator=(std::move(other));
detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_STD_IOSTREAM_MOVE)
// || defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
@@ -169,8 +243,7 @@ public:
explicit basic_socket_iostream(T... x)
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, StreamSocketService, Time,
TimeTraits, TimerService>::streambuf_)
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
if (rdbuf()->connect(x...) == 0)
@@ -208,14 +281,17 @@ public:
}

/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService>* rdbuf() const
basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService>*>(
return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(
&this->detail::socket_iostream_base<
Protocol, StreamSocketService, Time,
TimeTraits, TimerService>::streambuf_);
Protocol, Clock, WaitTraits>::streambuf_);
}

/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return rdbuf()->socket();
}

/// Get the last error associated with the stream.
@@ -232,7 +308,7 @@ public:
*/
const asio::error_code& error() const
{
return rdbuf()->puberror();
return rdbuf()->error();
}

#if !defined(ASIO_NO_DEPRECATED)
@@ -309,6 +385,12 @@ public:
rdbuf()->expires_from_now(expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)

private:
// Disallow copying and assignment.
basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED;
basic_socket_iostream& operator=(
const basic_socket_iostream&) ASIO_DELETED;
};

} // namespace asio


+ 357
- 316
source/modules/hylia/link/asio/basic_socket_streambuf.hpp View File

@@ -2,7 +2,7 @@
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -20,18 +20,22 @@
#if !defined(ASIO_NO_IOSTREAM)

#include <streambuf>
#include <vector>
#include "asio/basic_socket.hpp"
#include "asio/deadline_timer_service.hpp"
#include "asio/detail/array.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/io_context.hpp"
#include "asio/stream_socket_service.hpp"

#if defined(ASIO_HAS_BOOST_DATE_TIME)
# include "asio/deadline_timer.hpp"
#else
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include "asio/detail/deadline_timer_service.hpp"
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include "asio/steady_timer.hpp"
#endif
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)

#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)

@@ -39,14 +43,11 @@

// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// basic_socket_streambuf<Protocol, StreamSocketService,
// Time, TimeTraits, TimerService>* connect(
// T1 x1, ..., Tn xn)
// basic_socket_streambuf* connect(T1 x1, ..., Tn xn)
// {
// init_buffers();
// this->basic_socket<Protocol, StreamSocketService>::close(ec_);
// typedef typename Protocol::resolver resolver_type;
// resolver_type resolver(detail::socket_streambuf_base::io_context_);
// resolver_type resolver(socket().get_executor());
// connect_to_endpoints(
// resolver.resolve(x1, ..., xn, ec_));
// return !ec_ ? this : 0;
@@ -55,14 +56,11 @@

# define ASIO_PRIVATE_CONNECT_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
basic_socket_streambuf<Protocol, StreamSocketService, \
Time, TimeTraits, TimerService>* connect( \
ASIO_VARIADIC_BYVAL_PARAMS(n)) \
basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
init_buffers(); \
this->basic_socket<Protocol, StreamSocketService>::close(ec_); \
typedef typename Protocol::resolver resolver_type; \
resolver_type resolver(detail::socket_streambuf_base::io_context_); \
resolver_type resolver(socket().get_executor()); \
connect_to_endpoints( \
resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
return !ec_ ? this : 0; \
@@ -76,59 +74,111 @@
namespace asio {
namespace detail {

// A separate base class is used to ensure that the io_context is initialised
// prior to the basic_socket_streambuf's basic_socket base class.
class socket_streambuf_base
// A separate base class is used to ensure that the io_context member is
// initialised prior to the basic_socket_streambuf's basic_socket base class.
class socket_streambuf_io_context
{
protected:
socket_streambuf_io_context(io_context* ctx)
: default_io_context_(ctx)
{
}

shared_ptr<io_context> default_io_context_;
};

// A separate base class is used to ensure that the dynamically allocated
// buffers are constructed prior to the basic_socket_streambuf's basic_socket
// base class. This makes moving the socket is the last potentially throwing
// step in the streambuf's move constructor, giving the constructor a strong
// exception safety guarantee.
class socket_streambuf_buffers
{
protected:
io_context io_context_;
socket_streambuf_buffers()
: get_buffer_(buffer_size),
put_buffer_(buffer_size)
{
}

enum { buffer_size = 512 };
std::vector<char> get_buffer_;
std::vector<char> put_buffer_;
};

} // namespace detail

/// Iostream streambuf for a socket.
#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol>,
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
typename Time = boost::posix_time::ptime,
typename TimeTraits = asio::time_traits<Time>,
typename TimerService = deadline_timer_service<Time, TimeTraits> >
#else
typename Time = steady_timer::clock_type,
typename TimeTraits = steady_timer::traits_type,
typename TimerService = steady_timer::service_type>
#endif
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> >
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_streambuf;

#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)

/// Iostream streambuf for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_streambuf
: public std::streambuf,
private detail::socket_streambuf_base,
public basic_socket<Protocol, StreamSocketService>
private detail::socket_streambuf_io_context,
private detail::socket_streambuf_buffers,
#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
private basic_socket<Protocol>
#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
public basic_socket<Protocol>
#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateTime, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME)
typedef TimeTraits traits_helper;
#else
typedef detail::chrono_time_traits<Time, TimeTraits> traits_helper;
#endif
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)

public:
/// The protocol type.
typedef Protocol protocol_type;

/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;

/// The clock type.
typedef Clock clock_type;

#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename TimeTraits::time_type time_type;
typedef typename WaitTraits::time_type time_type;

/// The time type.
typedef typename TimeTraits::time_point time_point;
typedef typename WaitTraits::time_point time_point;

/// (Deprecated: Use duration.) The duration type.
typedef typename TimeTraits::duration_type duration_type;
typedef typename WaitTraits::duration_type duration_type;

/// The duration type.
typedef typename TimeTraits::duration duration;
typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
@@ -140,22 +190,64 @@ public:

/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
: basic_socket<Protocol, StreamSocketService>(
this->detail::socket_streambuf_base::io_context_),
unbuffered_(false),
timer_service_(0),
timer_state_(no_timer)
: detail::socket_streambuf_io_context(new io_context),
basic_socket<Protocol>(*default_io_context_),
expiry_time_(max_expiry_time())
{
init_buffers();
}

#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_streambuf from the supplied socket.
explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
: detail::socket_streambuf_io_context(0),
basic_socket<Protocol>(std::move(s)),
expiry_time_(max_expiry_time())
{
init_buffers();
}

/// Move-construct a basic_socket_streambuf from another.
basic_socket_streambuf(basic_socket_streambuf&& other)
: detail::socket_streambuf_io_context(other),
basic_socket<Protocol>(std::move(other.socket())),
ec_(other.ec_),
expiry_time_(other.expiry_time_)
{
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = asio::error_code();
other.expiry_time_ = max_expiry_time();
other.init_buffers();
}

/// Move-assign a basic_socket_streambuf from another.
basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
{
this->close();
socket() = std::move(other.socket());
detail::socket_streambuf_io_context::operator=(other);
ec_ = other.ec_;
expiry_time_ = other.expiry_time_;
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = asio::error_code();
other.expiry_time_ = max_expiry_time();
other.put_buffer_.resize(buffer_size);
other.init_buffers();
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());

destroy_timer();
}

/// Establish a connection.
@@ -165,29 +257,11 @@ public:
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService>* connect(
const endpoint_type& endpoint)
basic_socket_streambuf* connect(const endpoint_type& endpoint)
{
init_buffers();

this->basic_socket<Protocol, StreamSocketService>::close(ec_);

if (timer_state_ == timer_has_expired)
{
ec_ = asio::error::operation_aborted;
return 0;
}

io_handler handler = { this };
this->basic_socket<Protocol, StreamSocketService>::async_connect(
endpoint, handler);

ec_ = asio::error::would_block;
this->get_service().get_io_context().restart();
do this->get_service().get_io_context().run_one();
while (ec_ == asio::error::would_block);

ec_ = asio::error_code();
this->connect_to_endpoints(&endpoint, &endpoint + 1);
return !ec_ ? this : 0;
}

@@ -202,17 +276,14 @@ public:
* pointer otherwise.
*/
template <typename T1, ..., typename TN>
basic_socket_streambuf<Protocol, StreamSocketService>* connect(
T1 t1, ..., TN tn);
basic_socket_streambuf* connect(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T>
basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService>* connect(T... x)
basic_socket_streambuf* connect(T... x)
{
init_buffers();
this->basic_socket<Protocol, StreamSocketService>::close(ec_);
typedef typename Protocol::resolver resolver_type;
resolver_type resolver(detail::socket_streambuf_base::io_context_);
resolver_type resolver(socket().get_executor());
connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0;
}
@@ -225,17 +296,34 @@ public:
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf<Protocol, StreamSocketService,
Time, TimeTraits, TimerService>* close()
basic_socket_streambuf* close()
{
sync();
this->basic_socket<Protocol, StreamSocketService>::close(ec_);
socket().close(ec_);
if (!ec_)
init_buffers();
return !ec_ ? this : 0;
}

/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return *this;
}

/// Get the last error associated with the stream buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
const asio::error_code& error() const
{
return ec_;
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use error().) Get the last error associated with the stream
/// buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
@@ -245,7 +333,6 @@ public:
return error();
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an
/// absolute time.
/**
@@ -254,9 +341,7 @@ public:
*/
time_point expires_at() const
{
return timer_service_
? timer_service_->expires_at(timer_implementation_)
: time_point();
return expiry_time_;
}
#endif // !defined(ASIO_NO_DEPRECATED)

@@ -267,13 +352,7 @@ public:
*/
time_point expiry() const
{
return timer_service_
#if defined(ASIO_HAS_BOOST_DATE_TIME)
? timer_service_->expires_at(timer_implementation_)
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
? timer_service_->expiry(timer_implementation_)
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
: time_point();
return expiry_time_;
}

/// Set the stream buffer's expiry time as an absolute time.
@@ -287,33 +366,7 @@ public:
*/
void expires_at(const time_point& expiry_time)
{
construct_timer();

asio::error_code ec;
timer_service_->expires_at(timer_implementation_, expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");

start_timer();
}

/// Set the stream buffer's expiry time relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_at(const duration& expiry_time)
{
construct_timer();

asio::error_code ec;
timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");

start_timer();
expiry_time_ = expiry_time;
}

/// Set the stream buffer's expiry time relative to now.
@@ -327,17 +380,7 @@ public:
*/
void expires_after(const duration& expiry_time)
{
construct_timer();

asio::error_code ec;
#if defined(ASIO_HAS_BOOST_DATE_TIME)
timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
timer_service_->expires_after(timer_implementation_, expiry_time, ec);
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
asio::detail::throw_error(ec, "after");

start_timer();
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}

#if !defined(ASIO_NO_DEPRECATED)
@@ -363,108 +406,124 @@ public:
*/
void expires_from_now(const duration& expiry_time)
{
construct_timer();

asio::error_code ec;
timer_service_->expires_from_now(timer_implementation_, expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");

start_timer();
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)

protected:
int_type underflow()
{
if (gptr() == egptr())
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(ASIO_WINDOWS_RUNTIME)
if (gptr() != egptr())
return traits_type::eof();

for (;;)
{
if (timer_state_ == timer_has_expired)
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = asio::error::operation_aborted;
ec_ = asio::error::timed_out;
return traits_type::eof();
}

io_handler handler = { this };
this->get_service().async_receive(this->get_implementation(),
asio::buffer(asio::buffer(get_buffer_) + putback_max),
0, handler);
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
bufs(asio::buffer(get_buffer_) + putback_max);
detail::signed_size_type bytes = detail::socket_ops::recv(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);

ec_ = asio::error::would_block;
this->get_service().get_io_context().restart();
do this->get_service().get_io_context().run_one();
while (ec_ == asio::error::would_block);
if (ec_)
// Check if operation succeeded.
if (bytes > 0)
{
setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max + bytes);
return traits_type::to_int_type(*gptr());
}

// Check for EOF.
if (bytes == 0)
{
ec_ = asio::error::eof;
return traits_type::eof();
}

// Operation failed.
if (ec_ != asio::error::would_block
&& ec_ != asio::error::try_again)
return traits_type::eof();

setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max + bytes_transferred_);
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
// Wait for socket to become ready.
if (detail::socket_ops::poll_read(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
#endif // defined(ASIO_WINDOWS_RUNTIME)
}

int_type overflow(int_type c)
{
if (unbuffered_)
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(ASIO_WINDOWS_RUNTIME)
char_type ch = traits_type::to_char_type(c);

// Determine what needs to be sent.
const_buffer output_buffer;
if (put_buffer_.empty())
{
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c); // Nothing to do.
output_buffer = asio::buffer(&ch, sizeof(char_type));
}
else
{
output_buffer = asio::buffer(pbase(),
(pptr() - pbase()) * sizeof(char_type));
}

while (output_buffer.size() > 0)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
// Nothing to do.
return traits_type::not_eof(c);
ec_ = asio::error::timed_out;
return traits_type::eof();
}
else

// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<
const_buffer, const_buffer> bufs(output_buffer);
detail::signed_size_type bytes = detail::socket_ops::send(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);

// Check if operation succeeded.
if (bytes > 0)
{
if (timer_state_ == timer_has_expired)
{
ec_ = asio::error::operation_aborted;
return traits_type::eof();
}

// Send the single character immediately.
char_type ch = traits_type::to_char_type(c);
io_handler handler = { this };
this->get_service().async_send(this->get_implementation(),
asio::buffer(&ch, sizeof(char_type)), 0, handler);

ec_ = asio::error::would_block;
this->get_service().get_io_context().restart();
do this->get_service().get_io_context().run_one();
while (ec_ == asio::error::would_block);
if (ec_)
return traits_type::eof();

return c;
output_buffer += static_cast<std::size_t>(bytes);
continue;
}

// Operation failed.
if (ec_ != asio::error::would_block
&& ec_ != asio::error::try_again)
return traits_type::eof();

// Wait for socket to become ready.
if (detail::socket_ops::poll_write(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
else

if (!put_buffer_.empty())
{
// Send all data in the output buffer.
asio::const_buffer buffer =
asio::buffer(pbase(), pptr() - pbase());
while (buffer.size() > 0)
{
if (timer_state_ == timer_has_expired)
{
ec_ = asio::error::operation_aborted;
return traits_type::eof();
}

io_handler handler = { this };
this->get_service().async_send(this->get_implementation(),
asio::buffer(buffer), 0, handler);

ec_ = asio::error::would_block;
this->get_service().get_io_context().restart();
do this->get_service().get_io_context().run_one();
while (ec_ == asio::error::would_block);
if (ec_)
return traits_type::eof();

buffer = buffer + bytes_transferred_;
}
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());

// If the new character is eof then our work here is done.
@@ -472,10 +531,12 @@ protected:
return traits_type::not_eof(c);

// Add the new character to the output buffer.
*pptr() = traits_type::to_char_type(c);
*pptr() = ch;
pbump(1);
return c;
}

return c;
#endif // defined(ASIO_WINDOWS_RUNTIME)
}

int sync()
@@ -487,150 +548,130 @@ protected:
{
if (pptr() == pbase() && s == 0 && n == 0)
{
unbuffered_ = true;
put_buffer_.clear();
setp(0, 0);
sync();
return this;
}

return 0;
}

/// Get the last error associated with the stream buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
virtual const asio::error_code& error() const
{
return ec_;
}

private:
// Disallow copying and assignment.
basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED;
basic_socket_streambuf& operator=(
const basic_socket_streambuf&) ASIO_DELETED;

void init_buffers()
{
setg(&get_buffer_[0],
&get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max);
if (unbuffered_)

if (put_buffer_.empty())
setp(0, 0);
else
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
}

template <typename EndpointSequence>
void connect_to_endpoints(const EndpointSequence& endpoints)
int timeout() const
{
if (!ec_)
{
typename EndpointSequence::iterator i = endpoints.begin();
typename EndpointSequence::iterator end = endpoints.end();
ec_ = asio::error::host_not_found;
while (ec_ && i != end)
{
this->basic_socket<Protocol, StreamSocketService>::close(ec_);

if (timer_state_ == timer_has_expired)
{
ec_ = asio::error::operation_aborted;
return;
}

io_handler handler = { this };
this->basic_socket<Protocol, StreamSocketService>::async_connect(
*i, handler);

ec_ = asio::error::would_block;
this->get_service().get_io_context().restart();
do this->get_service().get_io_context().run_one();
while (ec_ == asio::error::would_block);

++i;
}
}
int64_t msec = traits_helper::to_posix_duration(
traits_helper::subtract(expiry_time_,
traits_helper::now())).total_milliseconds();
if (msec > (std::numeric_limits<int>::max)())
msec = (std::numeric_limits<int>::max)();
else if (msec < 0)
msec = 0;
return static_cast<int>(msec);
}

struct io_handler;
friend struct io_handler;
struct io_handler
template <typename EndpointSequence>
void connect_to_endpoints(const EndpointSequence& endpoints)
{
basic_socket_streambuf* this_;

void operator()(const asio::error_code& ec,
std::size_t bytes_transferred = 0)
{
this_->ec_ = ec;
this_->bytes_transferred_ = bytes_transferred;
}
};
this->connect_to_endpoints(endpoints.begin(), endpoints.end());
}

struct timer_handler;
friend struct timer_handler;
struct timer_handler
template <typename EndpointIterator>
void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
{
basic_socket_streambuf* this_;

void operator()(const asio::error_code&)
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
#else // defined(ASIO_WINDOWS_RUNTIME)
if (ec_)
return;

ec_ = asio::error::not_found;
for (EndpointIterator i = begin; i != end; ++i)
{
time_point now = traits_helper::now();

#if defined(ASIO_HAS_BOOST_DATE_TIME)
time_point expiry_time = this_->timer_service_->expires_at(
this_->timer_implementation_);
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
time_point expiry_time = this_->timer_service_->expiry(
this_->timer_implementation_);
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)

if (traits_helper::less_than(now, expiry_time))
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
this_->timer_state_ = timer_is_pending;
this_->timer_service_->async_wait(this_->timer_implementation_, *this);
ec_ = asio::error::timed_out;
return;
}
else
{
this_->timer_state_ = timer_has_expired;
asio::error_code ec;
this_->basic_socket<Protocol, StreamSocketService>::close(ec);
}
}
};

void construct_timer()
{
if (timer_service_ == 0)
{
TimerService& timer_service = use_service<TimerService>(
detail::socket_streambuf_base::io_context_);
timer_service.construct(timer_implementation_);
timer_service_ = &timer_service;
// Close and reopen the socket.
typename Protocol::endpoint ep(*i);
socket().close(ec_);
socket().open(ep.protocol(), ec_);
if (ec_)
continue;

// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::socket_ops::connect(socket().native_handle(),
ep.data(), ep.size(), ec_);

// Check if operation succeeded.
if (!ec_)
return;

// Operation failed.
if (ec_ != asio::error::in_progress
&& ec_ != asio::error::would_block)
continue;

// Wait for socket to become ready.
if (detail::socket_ops::poll_connect(
socket().native_handle(), timeout(), ec_) < 0)
continue;

// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
== detail::socket_error_retval)
return;

// Check the result of the connect operation.
ec_ = asio::error_code(connect_error,
asio::error::get_system_category());
if (!ec_)
return;
}
#endif // defined(ASIO_WINDOWS_RUNTIME)
}

void destroy_timer()
// Helper function to get the maximum expiry time.
static time_point max_expiry_time()
{
if (timer_service_)
timer_service_->destroy(timer_implementation_);
}

void start_timer()
{
if (timer_state_ != timer_is_pending)
{
timer_handler handler = { this };
handler(asio::error_code());
}
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return boost::posix_time::pos_infin;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return (time_point::max)();
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
}

enum { putback_max = 8 };
enum { buffer_size = 512 };
asio::detail::array<char, buffer_size> get_buffer_;
asio::detail::array<char, buffer_size> put_buffer_;
bool unbuffered_;
asio::error_code ec_;
std::size_t bytes_transferred_;
TimerService* timer_service_;
typename TimerService::implementation_type timer_implementation_;
enum state { no_timer, timer_is_pending, timer_has_expired } timer_state_;
time_point expiry_time_;
};

} // namespace asio


+ 264
- 119
source/modules/hylia/link/asio/basic_stream_socket.hpp View File

@@ -2,7 +2,7 @@
// basic_stream_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -20,14 +20,23 @@
#include "asio/async_result.hpp"
#include "asio/basic_socket.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/stream_socket_service.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {

#if !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)
#define ASIO_BASIC_STREAM_SOCKET_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = executor>
class basic_stream_socket;

#endif // !defined(ASIO_BASIC_STREAM_SOCKET_FWD_DECL)

/// Provides stream-oriented socket functionality.
/**
* The basic_stream_socket class template provides asynchronous and blocking
@@ -40,14 +49,29 @@ namespace asio {
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Protocol,
typename StreamSocketService = stream_socket_service<Protocol> >
template <typename Protocol, typename Executor>
class basic_stream_socket
: public basic_socket<Protocol, StreamSocketService>
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_stream_socket<Protocol, Executor1> other;
};

/// The native representation of a socket.
typedef typename StreamSocketService::native_handle_type native_handle_type;
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif

/// The protocol type.
typedef Protocol protocol_type;
@@ -61,11 +85,30 @@ public:
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_stream_socket(asio::io_context& io_context)
: basic_socket<Protocol, StreamSocketService>(io_context)
explicit basic_stream_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}

/// Construct a basic_stream_socket without opening it.
/**
* This constructor creates a stream socket without opening it. The socket
* needs to be opened and then connected or accepted before data can be sent
* or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_stream_socket(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context)
{
}

@@ -74,16 +117,37 @@ public:
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
const protocol_type& protocol)
: basic_socket<Protocol, StreamSocketService>(io_context, protocol)
basic_stream_socket(const executor_type& ex, const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}

/// Construct and open a basic_stream_socket.
/**
* This constructor creates and opens a stream socket. The socket needs to be
* connected or accepted before data can be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context, const protocol_type& protocol,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol)
{
}

@@ -94,7 +158,7 @@ public:
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
@@ -102,9 +166,33 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
const endpoint_type& endpoint)
: basic_socket<Protocol, StreamSocketService>(io_context, endpoint)
basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}

/// Construct a basic_stream_socket, opening it and binding it to the given
/// local endpoint.
/**
* This constructor creates a stream socket and automatically opens it bound
* to the specified endpoint on the local machine. The protocol used is the
* protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the stream
* socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}

@@ -113,7 +201,7 @@ public:
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param io_context The io_context object that the stream socket will use to
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
@@ -122,10 +210,34 @@ public:
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_socket(asio::io_context& io_context,
basic_stream_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, StreamSocketService>(
io_context, protocol, native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}

/// Construct a basic_stream_socket on an existing native socket.
/**
* This constructor creates a stream socket object to hold an existing native
* socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}

@@ -138,11 +250,11 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
basic_stream_socket(basic_stream_socket&& other)
: basic_socket<Protocol, StreamSocketService>(
ASIO_MOVE_CAST(basic_stream_socket)(other))
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -154,12 +266,12 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
basic_stream_socket& operator=(basic_stream_socket&& other)
{
basic_socket<Protocol, StreamSocketService>::operator=(
ASIO_MOVE_CAST(basic_stream_socket)(other));
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}

@@ -172,15 +284,16 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename StreamSocketService1>
basic_stream_socket(
basic_stream_socket<Protocol1, StreamSocketService1>&& other,
typename enable_if<is_convertible<Protocol1, Protocol>::value>::type* = 0)
: basic_socket<Protocol, StreamSocketService>(
ASIO_MOVE_CAST2(basic_stream_socket<
Protocol1, StreamSocketService1>)(other))
template <typename Protocol1, typename Executor1>
basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other,
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type* = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}

@@ -192,20 +305,30 @@ public:
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_socket(io_context&) constructor.
* constructed using the @c basic_stream_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename StreamSocketService1>
typename enable_if<is_convertible<Protocol1, Protocol>::value,
basic_stream_socket>::type& operator=(
basic_stream_socket<Protocol1, StreamSocketService1>&& other)
{
basic_socket<Protocol, StreamSocketService>::operator=(
ASIO_MOVE_CAST2(basic_stream_socket<
Protocol1, StreamSocketService1>)(other));
template <typename Protocol1, typename Executor1>
typename enable_if<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_stream_socket&
>::type operator=(basic_stream_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_stream_socket()
{
}

/// Send some data on the socket.
/**
* This function is used to send data on the stream socket. The function
@@ -235,8 +358,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -273,8 +396,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send");
return s;
}
@@ -301,8 +424,8 @@ public:
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().send(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous send.
@@ -323,9 +446,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@@ -346,13 +469,10 @@ public:
async_send(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(
this->get_implementation(), buffers, 0,
ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous send.
@@ -375,9 +495,9 @@ public:
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@@ -399,13 +519,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(
this->get_implementation(), buffers, flags,
ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this, buffers, flags);
}

/// Receive some data on the socket.
@@ -440,8 +556,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -481,8 +597,8 @@ public:
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
@@ -509,8 +625,8 @@ public:
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->get_service().receive(
this->get_implementation(), buffers, flags, ec);
return this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, flags, ec);
}

/// Start an asynchronous receive.
@@ -531,9 +647,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
@@ -556,12 +672,10 @@ public:
async_receive(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Start an asynchronous receive.
@@ -584,9 +698,9 @@ public:
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref async_read function if you need to ensure
@@ -610,12 +724,9 @@ public:
socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, flags, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this, buffers, flags);
}

/// Write some data to the socket.
@@ -649,8 +760,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().send(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
@@ -675,7 +786,8 @@ public:
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->get_service().send(this->get_implementation(), buffers, 0, ec);
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, 0, ec);
}

/// Start an asynchronous write.
@@ -696,9 +808,9 @@ public:
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
@@ -719,12 +831,10 @@ public:
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

return this->get_service().async_send(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(WriteHandler)(handler));
return async_initiate<WriteHandler,
void (asio::error_code, std::size_t)>(
initiate_async_send(), handler, this,
buffers, socket_base::message_flags(0));
}

/// Read some data from the socket.
@@ -759,8 +869,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->get_service().receive(
this->get_implementation(), buffers, 0, ec);
std::size_t s = this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, 0, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
@@ -786,8 +896,8 @@ public:
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->get_service().receive(
this->get_implementation(), buffers, 0, ec);
return this->impl_.get_service().receive(
this->impl_.get_implementation(), buffers, 0, ec);
}

/// Start an asynchronous read.
@@ -808,9 +918,9 @@ public:
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
@@ -832,13 +942,48 @@ public:
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

return this->get_service().async_receive(this->get_implementation(),
buffers, 0, ASIO_MOVE_CAST(ReadHandler)(handler));
return async_initiate<ReadHandler,
void (asio::error_code, std::size_t)>(
initiate_async_receive(), handler, this,
buffers, socket_base::message_flags(0));
}

private:
struct initiate_async_send
{
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
basic_stream_socket* self, const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;

detail::non_const_lvalue<WriteHandler> handler2(handler);
self->impl_.get_service().async_send(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};

struct initiate_async_receive
{
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
basic_stream_socket* self, const MutableBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;

detail::non_const_lvalue<ReadHandler> handler2(handler);
self->impl_.get_service().async_receive(
self->impl_.get_implementation(), buffers, flags,
handler2.value, self->impl_.get_implementation_executor());
}
};
};

} // namespace asio


+ 4
- 5
source/modules/hylia/link/asio/basic_streambuf.hpp View File

@@ -2,7 +2,7 @@
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -119,8 +119,8 @@ public:
/// The type used to represent the output sequence as a list of buffers.
typedef implementation_defined mutable_buffers_type;
#else
typedef asio::const_buffers_1 const_buffers_type;
typedef asio::mutable_buffers_1 mutable_buffers_type;
typedef ASIO_CONST_BUFFER const_buffers_type;
typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
#endif

/// Construct a basic_streambuf object.
@@ -232,8 +232,7 @@ public:
*/
void commit(std::size_t n)
{
if (pptr() + n > epptr())
n = epptr() - pptr();
n = std::min<std::size_t>(n, epptr() - pptr());
pbump(static_cast<int>(n));
setg(eback(), gptr(), pptr());
}


+ 1
- 1
source/modules/hylia/link/asio/basic_streambuf_fwd.hpp View File

@@ -2,7 +2,7 @@
// basic_streambuf_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 197
- 95
source/modules/hylia/link/asio/basic_waitable_timer.hpp View File

@@ -2,7 +2,7 @@
// basic_waitable_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -17,17 +17,35 @@

#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/basic_io_object.hpp"
#include "asio/detail/chrono_time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/executor.hpp"
#include "asio/wait_traits.hpp"
#include "asio/waitable_timer_service.hpp"

#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)

#include "asio/detail/push_options.hpp"

namespace asio {

#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL

// Forward declaration with defaulted arguments.
template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock>,
typename Executor = executor>
class basic_waitable_timer;

#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)

/// Provides waitable timer functionality.
/**
* The basic_waitable_timer class template provides the ability to perform a
@@ -51,7 +69,7 @@ namespace asio {
* Performing a blocking wait (C++11):
* @code
* // Construct a timer without setting an expiry time.
* asio::steady_timer timer(io_context);
* asio::steady_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_after(std::chrono::seconds(5));
@@ -74,7 +92,7 @@ namespace asio {
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::steady_timer timer(io_context,
* asio::steady_timer timer(my_context,
* std::chrono::steady_clock::now() + std::chrono::seconds(60));
*
* // Start an asynchronous wait.
@@ -120,13 +138,13 @@ namespace asio {
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock>,
typename WaitableTimerService = waitable_timer_service<Clock, WaitTraits> >
template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer
: public basic_io_object<WaitableTimerService>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;

/// The clock type.
typedef Clock clock_type;

@@ -145,30 +163,72 @@ public:
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_waitable_timer(const executor_type& ex)
: impl_(ex)
{
}

/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
}

/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor object that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
explicit basic_waitable_timer(asio::io_context& io_context)
: basic_io_object<WaitableTimerService>(io_context)
basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
: impl_(ex)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}

/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_waitable_timer(asio::io_context& io_context,
const time_point& expiry_time)
: basic_io_object<WaitableTimerService>(io_context)
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const time_point& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
this->get_service().expires_at(this->get_implementation(), expiry_time, ec);
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}

@@ -176,19 +236,43 @@ public:
/**
* This constructor creates a timer and sets the expiry time.
*
* @param io_context The io_context object that the timer will use to dispatch
* handlers for any asynchronous operations performed on the timer.
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_waitable_timer(asio::io_context& io_context,
const duration& expiry_time)
: basic_io_object<WaitableTimerService>(io_context)
basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
: impl_(ex)
{
asio::error_code ec;
this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}

/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const duration& expiry_time,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0)
: impl_(context)
{
asio::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}

@@ -201,32 +285,48 @@ public:
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor.
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer(basic_waitable_timer&& other)
: basic_io_object<WaitableTimerService>(
ASIO_MOVE_CAST(basic_waitable_timer)(other))
: impl_(std::move(other.impl_))
{
}

/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another.
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(io_context&) constructor.
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer& operator=(basic_waitable_timer&& other)
{
basic_io_object<WaitableTimerService>::operator=(
ASIO_MOVE_CAST(basic_waitable_timer)(other));
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_waitable_timer()
{
}

/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}

/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
@@ -252,12 +352,14 @@ public:
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel(this->get_implementation(), ec);
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
return s;
}

/// Cancel any asynchronous operations that are waiting on the timer.
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancel any asynchronous
/// operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
@@ -281,8 +383,9 @@ public:
*/
std::size_t cancel(asio::error_code& ec)
{
return this->get_service().cancel(this->get_implementation(), ec);
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)

/// Cancels one asynchronous operation that is waiting on the timer.
/**
@@ -311,13 +414,15 @@ public:
std::size_t cancel_one()
{
asio::error_code ec;
std::size_t s = this->get_service().cancel_one(
this->get_implementation(), ec);
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one");
return s;
}

/// Cancels one asynchronous operation that is waiting on the timer.
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancels one asynchronous
/// operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
@@ -343,10 +448,9 @@ public:
*/
std::size_t cancel_one(asio::error_code& ec)
{
return this->get_service().cancel_one(this->get_implementation(), ec);
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute
/// time.
/**
@@ -355,7 +459,7 @@ public:
*/
time_point expires_at() const
{
return this->get_service().expires_at(this->get_implementation());
return impl_.get_service().expires_at(impl_.get_implementation());
}
#endif // !defined(ASIO_NO_DEPRECATED)

@@ -366,7 +470,7 @@ public:
*/
time_point expiry() const
{
return this->get_service().expiry(this->get_implementation());
return impl_.get_service().expiry(impl_.get_implementation());
}

/// Set the timer's expiry time as an absolute time.
@@ -394,13 +498,15 @@ public:
std::size_t expires_at(const time_point& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
return s;
}

/// Set the timer's expiry time as an absolute time.
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as
/// an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
@@ -425,9 +531,10 @@ public:
std::size_t expires_at(const time_point& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_at(
this->get_implementation(), expiry_time, ec);
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)

/// Set the timer's expiry time relative to now.
/**
@@ -454,41 +561,12 @@ public:
std::size_t expires_after(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
std::size_t s = impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
return s;
}

/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_after() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_after(const duration& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_after(
this->get_implementation(), expiry_time, ec);
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the timer's expiry time relative to now.
/**
@@ -497,7 +575,7 @@ public:
*/
duration expires_from_now() const
{
return this->get_service().expires_from_now(this->get_implementation());
return impl_.get_service().expires_from_now(impl_.get_implementation());
}

/// (Deprecated: Use expires_after().) Set the timer's expiry time relative
@@ -526,8 +604,8 @@ public:
std::size_t expires_from_now(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
return s;
}
@@ -558,8 +636,8 @@ public:
std::size_t expires_from_now(const duration& expiry_time,
asio::error_code& ec)
{
return this->get_service().expires_from_now(
this->get_implementation(), expiry_time, ec);
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)

@@ -573,7 +651,7 @@ public:
void wait()
{
asio::error_code ec;
this->get_service().wait(this->get_implementation(), ec);
impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}

@@ -586,7 +664,7 @@ public:
*/
void wait(asio::error_code& ec)
{
this->get_service().wait(this->get_implementation(), ec);
impl_.get_service().wait(impl_.get_implementation(), ec);
}

/// Start an asynchronous wait on the timer.
@@ -609,22 +687,46 @@ public:
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*/
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(ASIO_MOVE_ARG(WaitHandler) handler)
{
// If you get an error on the following line it means that your handler does
// not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;

return this->get_service().async_wait(this->get_implementation(),
ASIO_MOVE_CAST(WaitHandler)(handler));
return async_initiate<WaitHandler, void (asio::error_code)>(
initiate_async_wait(), handler, this);
}

private:
// Disallow copying and assignment.
basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED;
basic_waitable_timer& operator=(
const basic_waitable_timer&) ASIO_DELETED;

struct initiate_async_wait
{
template <typename WaitHandler>
void operator()(ASIO_MOVE_ARG(WaitHandler) handler,
basic_waitable_timer* self) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;

detail::non_const_lvalue<WaitHandler> handler2(handler);
self->impl_.get_service().async_wait(
self->impl_.get_implementation(), handler2.value,
self->impl_.get_implementation_executor());
}
};

detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits> >,
executor_type > impl_;
};

} // namespace asio


+ 20
- 18
source/modules/hylia/link/asio/bind_executor.hpp View File

@@ -2,7 +2,7 @@
// bind_executor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -18,9 +18,11 @@
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/associated_executor.hpp"
#include "asio/associated_allocator.hpp"
#include "asio/async_result.hpp"
#include "asio/handler_type.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/uses_executor.hpp"

#include "asio/detail/push_options.hpp"
@@ -166,27 +168,27 @@ class executor_binder_base<T, Executor, true>
protected:
template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
: Executor(ASIO_MOVE_CAST(E)(e)),
target_(executor_arg_t(), static_cast<const Executor&>(*this),
ASIO_MOVE_CAST(U)(u))
: executor_(ASIO_MOVE_CAST(E)(e)),
target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u))
{
}

Executor executor_;
T target_;
};

template <typename T, typename Executor>
class executor_binder_base<T, Executor, false>
: protected Executor
{
protected:
template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
: Executor(ASIO_MOVE_CAST(E)(e)),
: executor_(ASIO_MOVE_CAST(E)(e)),
target_(ASIO_MOVE_CAST(U)(u))
{
}

Executor executor_;
T target_;
};

@@ -393,7 +395,7 @@ public:
/// Obtain the associated executor.
executor_type get_executor() const ASIO_NOEXCEPT
{
return static_cast<const Executor&>(*this);
return this->executor_;
}

#if defined(GENERATING_DOCUMENTATION)
@@ -519,30 +521,30 @@ struct uses_executor<executor_binder<T, Executor>, Executor>
: true_type {};

template <typename T, typename Executor, typename Signature>
struct handler_type<executor_binder<T, Executor>, Signature>
class async_result<executor_binder<T, Executor>, Signature>
{
public:
typedef executor_binder<
typename handler_type<T, Signature>::type, Executor> type;
};
typename async_result<T, Signature>::completion_handler_type, Executor>
completion_handler_type;

template <typename T, typename Executor>
class async_result<executor_binder<T, Executor> >
{
public:
typedef typename async_result<T>::type type;
typedef typename async_result<T, Signature>::return_type return_type;

explicit async_result(executor_binder<T, Executor>& b)
: target_(b.get())
{
}

type get()
return_type get()
{
return target_.get();
}

private:
async_result<T> target_;
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;

async_result<T, Signature> target_;
};

template <typename T, typename Executor, typename Allocator>


+ 1081
- 1312
source/modules/hylia/link/asio/buffer.hpp
File diff suppressed because it is too large
View File


+ 6
- 28
source/modules/hylia/link/asio/buffered_read_stream.hpp View File

@@ -2,7 +2,7 @@
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -26,7 +26,6 @@
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"

#include "asio/detail/push_options.hpp"

@@ -105,22 +104,6 @@ public:
return next_layer_.lowest_layer().get_executor();
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return next_layer_.get_io_context();
}

/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return next_layer_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)

/// Close the stream.
void close()
{
@@ -128,9 +111,10 @@ public:
}

/// Close the stream.
asio::error_code close(asio::error_code& ec)
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
return next_layer_.close(ec);
next_layer_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Write the given data to the stream. Returns the number of bytes written.
@@ -158,14 +142,8 @@ public:
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler)
{
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);

next_layer_.async_write_some(buffers,
ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(WriteHandler,
void (asio::error_code, std::size_t)))(init.handler));

return init.result.get();
return next_layer_.async_write_some(buffers,
ASIO_MOVE_CAST(WriteHandler)(handler));
}

/// Fill the buffer with some data. Returns the number of bytes placed in the


+ 1
- 1
source/modules/hylia/link/asio/buffered_read_stream_fwd.hpp View File

@@ -2,7 +2,7 @@
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 4
- 20
source/modules/hylia/link/asio/buffered_stream.hpp View File

@@ -2,7 +2,7 @@
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -23,7 +23,6 @@
#include "asio/buffered_stream_fwd.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"

#include "asio/detail/push_options.hpp"

@@ -96,22 +95,6 @@ public:
return stream_impl_.lowest_layer().get_executor();
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return stream_impl_.get_io_context();
}

/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return stream_impl_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)

/// Close the stream.
void close()
{
@@ -119,9 +102,10 @@ public:
}

/// Close the stream.
asio::error_code close(asio::error_code& ec)
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
return stream_impl_.close(ec);
stream_impl_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Flush all data from the buffer to the next layer. Returns the number of


+ 1
- 1
source/modules/hylia/link/asio/buffered_stream_fwd.hpp View File

@@ -2,7 +2,7 @@
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 6
- 28
source/modules/hylia/link/asio/buffered_write_stream.hpp View File

@@ -2,7 +2,7 @@
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -25,7 +25,6 @@
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"
#include "asio/write.hpp"

#include "asio/detail/push_options.hpp"
@@ -105,22 +104,6 @@ public:
return next_layer_.lowest_layer().get_executor();
}

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_context()
{
return next_layer_.get_io_context();
}

/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
asio::io_context& get_io_service()
{
return next_layer_.get_io_service();
}
#endif // !defined(ASIO_NO_DEPRECATED)

/// Close the stream.
void close()
{
@@ -128,9 +111,10 @@ public:
}

/// Close the stream.
asio::error_code close(asio::error_code& ec)
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
return next_layer_.close(ec);
next_layer_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}

/// Flush all data from the buffer to the next layer. Returns the number of
@@ -193,14 +177,8 @@ public:
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler)
{
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);

next_layer_.async_read_some(buffers,
ASIO_MOVE_CAST(ASIO_HANDLER_TYPE(ReadHandler,
void (asio::error_code, std::size_t)))(init.handler));

return init.result.get();
return next_layer_.async_read_some(buffers,
ASIO_MOVE_CAST(ReadHandler)(handler));
}

/// Peek at the incoming data on the stream. Returns the number of bytes read.


+ 1
- 1
source/modules/hylia/link/asio/buffered_write_stream_fwd.hpp View File

@@ -2,7 +2,7 @@
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 52
- 12
source/modules/hylia/link/asio/buffers_iterator.hpp View File

@@ -2,7 +2,7 @@
// buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -65,7 +65,44 @@ namespace detail
typedef buffers_iterator_types_helper<is_mutable> helper;
typedef typename helper::buffer_type buffer_type;
typedef typename helper::template byte_type<ByteType>::type byte_type;
typedef typename BufferSequence::const_iterator const_iterator;
};

template <typename ByteType>
struct buffers_iterator_types<mutable_buffer, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};

template <typename ByteType>
struct buffers_iterator_types<const_buffer, ByteType>
{
typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type;
typedef const const_buffer* const_iterator;
};

#if !defined(ASIO_NO_DEPRECATED)

template <typename ByteType>
struct buffers_iterator_types<mutable_buffers_1, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};

template <typename ByteType>
struct buffers_iterator_types<const_buffers_1, ByteType>
{
typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type;
typedef const const_buffer* const_iterator;
};

#endif // !defined(ASIO_NO_DEPRECATED)
}

/// A random access iterator over the bytes in a buffer sequence.
@@ -76,6 +113,9 @@ private:
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::buffer_type buffer_type;

typedef typename detail::buffers_iterator_types<BufferSequence,
ByteType>::const_iterator buffer_sequence_iterator_type;

public:
/// The type used for the distance between two iterators.
typedef std::ptrdiff_t difference_type;
@@ -130,9 +170,9 @@ public:
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
new_iter.current_ = buffers.begin();
new_iter.end_ = buffers.end();
new_iter.begin_ = asio::buffer_sequence_begin(buffers);
new_iter.current_ = asio::buffer_sequence_begin(buffers);
new_iter.end_ = asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
new_iter.current_buffer_ = *new_iter.current_;
@@ -150,9 +190,9 @@ public:
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = buffers.begin();
new_iter.current_ = buffers.begin();
new_iter.end_ = buffers.end();
new_iter.begin_ = asio::buffer_sequence_begin(buffers);
new_iter.current_ = asio::buffer_sequence_begin(buffers);
new_iter.end_ = asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
buffer_type buffer = *new_iter.current_;
@@ -347,7 +387,7 @@ private:
}

// Find the previous non-empty buffer.
typename BufferSequence::const_iterator iter = current_;
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
@@ -426,7 +466,7 @@ private:
}

// Find the previous non-empty buffer.
typename BufferSequence::const_iterator iter = current_;
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
@@ -452,9 +492,9 @@ private:

buffer_type current_buffer_;
std::size_t current_buffer_position_;
typename BufferSequence::const_iterator begin_;
typename BufferSequence::const_iterator current_;
typename BufferSequence::const_iterator end_;
buffer_sequence_iterator_type begin_;
buffer_sequence_iterator_type current_;
buffer_sequence_iterator_type end_;
std::size_t position_;
};



+ 88
- 0
source/modules/hylia/link/asio/co_spawn.hpp View File

@@ -0,0 +1,88 @@
//
// co_spawn.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_CO_SPAWN_HPP
#define ASIO_CO_SPAWN_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"

#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)

#include "asio/awaitable.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace detail {

template <typename T>
struct awaitable_signature;

template <typename T, typename Executor>
struct awaitable_signature<awaitable<T, Executor>>
{
typedef void type(std::exception_ptr, T);
};

template <typename Executor>
struct awaitable_signature<awaitable<void, Executor>>
{
typedef void type(std::exception_ptr);
};

} // namespace detail

/// Spawn a new thread of execution.
/**
* The entry point function object @c f must have the signature:
*
* @code awaitable<void, E> f(); @endcode
*
* where @c E is convertible from @c Executor.
*/
template <typename Executor, typename F, typename CompletionToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
co_spawn(const Executor& ex, F&& f, CompletionToken&& token,
typename enable_if<
is_executor<Executor>::value
>::type* = 0);

/// Spawn a new thread of execution.
/**
* The entry point function object @c f must have the signature:
*
* @code awaitable<void, E> f(); @endcode
*
* where @c E is convertible from @c ExecutionContext::executor_type.
*/
template <typename ExecutionContext, typename F, typename CompletionToken>
ASIO_INITFN_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token,
typename enable_if<
is_convertible<ExecutionContext&, execution_context&>::value
>::type* = 0);

} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/impl/co_spawn.hpp"

#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)

#endif // ASIO_CO_SPAWN_HPP

+ 1
- 1
source/modules/hylia/link/asio/completion_condition.hpp View File

@@ -2,7 +2,7 @@
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 136
- 0
source/modules/hylia/link/asio/compose.hpp View File

@@ -0,0 +1,136 @@
//
// compose.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_COMPOSE_HPP
#define ASIO_COMPOSE_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include "asio/async_result.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {

#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
|| defined(GENERATING_DOCUMENTATION)

/// Launch an asynchronous operation with a stateful implementation.
/**
* The async_compose function simplifies the implementation of composed
* asynchronous operations automatically wrapping a stateful function object
* with a conforming intermediate completion handler.
*
* @param implementation A function object that contains the implementation of
* the composed asynchronous operation. The first argument to the function
* object is a non-const reference to the enclosing intermediate completion
* handler. The remaining arguments are any arguments that originate from the
* completion handlers of any asynchronous operations performed by the
* implementation.

* @param token The completion token.
*
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
* which outstanding work must be maintained.
*
* @par Example:
*
* @code struct async_echo_implementation
* {
* tcp::socket& socket_;
* asio::mutable_buffer buffer_;
* enum { starting, reading, writing } state_;
*
* template <typename Self>
* void operator()(Self& self,
* asio::error_code error = {},
* std::size_t n = 0)
* {
* switch (state_)
* {
* case starting:
* state_ = reading;
* socket_.async_read_some(
* buffer_, std::move(self));
* break;
* case reading:
* if (error)
* {
* self.complete(error, 0);
* }
* else
* {
* state_ = writing;
* asio::async_write(socket_, buffer_,
* asio::transfer_exactly(n),
* std::move(self));
* }
* break;
* case writing:
* self.complete(error, n);
* break;
* }
* }
* };
*
* template <typename CompletionToken>
* auto async_echo(tcp::socket& socket,
* asio::mutable_buffer buffer,
* CompletionToken&& token) ->
* typename asio::async_result<
* typename std::decay<CompletionToken>::type,
* void(asio::error_code, std::size_t)>::return_type
* {
* return asio::async_compose<CompletionToken,
* void(asio::error_code, std::size_t)>(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting},
* token, socket);
* } @endcode
*/
template <typename CompletionToken, typename Signature,
typename Implementation, typename... IoObjectsOrExecutors>
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)
async_compose(ASIO_MOVE_ARG(Implementation) implementation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors);

#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)

template <typename CompletionToken, typename Signature, typename Implementation>
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)
async_compose(ASIO_MOVE_ARG(Implementation) implementation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token);

#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \
template <typename CompletionToken, typename Signature, \
typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \
ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \
async_compose(ASIO_MOVE_ARG(Implementation) implementation, \
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n));
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)
#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF

#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)

} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/impl/compose.hpp"

#endif // ASIO_COMPOSE_HPP

+ 96
- 96
source/modules/hylia/link/asio/connect.hpp View File

@@ -2,7 +2,7 @@
// connect.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -58,7 +58,8 @@ struct is_endpoint_sequence
/**
* @defgroup connect asio::connect
*
* @brief Establishes a socket connection by trying each endpoint in a sequence.
* @brief The @c connect function is a composed operation that establishes a
* socket connection by trying each endpoint in a sequence.
*/
/*@{*/

@@ -81,13 +82,13 @@ struct is_endpoint_sequence
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::connect(s, r.resolve(q)); @endcode
*/
template <typename Protocol, typename SocketService, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@@ -112,9 +113,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* default-constructed endpoint.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* asio::connect(s, r.resolve(q), ec);
* if (ec)
@@ -122,15 +123,15 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* // An error occurred.
* } @endcode
*/
template <typename Protocol, typename SocketService, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
template <typename Protocol, typename Executor, typename EndpointSequence>
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated.) Establishes a socket connection by trying each endpoint in a
/// sequence.
/// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
@@ -153,12 +154,12 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService, typename Iterator>
Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);

/// (Deprecated.) Establishes a socket connection by trying each endpoint in a
/// sequence.
/// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
@@ -181,8 +182,8 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService, typename Iterator>
Iterator connect(basic_socket<Protocol, SocketService>& s,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)
@@ -208,14 +209,14 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* Otherwise, contains the error from the last connection attempt.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::connect(s, e.begin(), e.end()); @endcode
*/
template <typename Protocol, typename SocketService, typename Iterator>
Iterator connect(basic_socket<Protocol, SocketService>& s,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end);

/// Establishes a socket connection by trying each endpoint in a sequence.
@@ -240,10 +241,10 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* endpoint. Otherwise, the end iterator.
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* asio::connect(s, e.begin(), e.end(), ec);
* if (ec)
@@ -251,8 +252,8 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* // An error occurred.
* } @endcode
*/
template <typename Protocol, typename SocketService, typename Iterator>
Iterator connect(basic_socket<Protocol, SocketService>& s,
template <typename Protocol, typename Executor, typename Iterator>
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, asio::error_code& ec);

/// Establishes a socket connection by trying each endpoint in a sequence.
@@ -299,16 +300,16 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition());
* std::cout << "Connected to: " << e << std::endl; @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);
@@ -358,9 +359,9 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* tcp::endpoint e = asio::connect(s,
* r.resolve(q), my_connect_condition(), ec);
@@ -373,17 +374,17 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* std::cout << "Connected to: " << e << std::endl;
* } @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename ConnectCondition>
typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
asio::error_code& ec,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated.) Establishes a socket connection by trying each endpoint in a
/// sequence.
/// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
@@ -417,14 +418,14 @@ typename Protocol::endpoint connect(basic_socket<Protocol, SocketService>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, SocketService>& s,
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, ConnectCondition connect_condition,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);

/// (Deprecated.) Establishes a socket connection by trying each endpoint in a
/// sequence.
/// (Deprecated: Use range overload.) Establishes a socket connection by trying
/// each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c connect member
@@ -458,9 +459,9 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition, asio::error_code& ec,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)
@@ -511,17 +512,17 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition());
* std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition);

/// Establishes a socket connection by trying each endpoint in a sequence.
@@ -571,10 +572,10 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::resolver::results_type e = r.resolve(q);
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::error_code ec;
* tcp::resolver::results_type::iterator i = asio::connect(
* s, e.begin(), e.end(), my_connect_condition());
@@ -587,9 +588,9 @@ Iterator connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* std::cout << "Connected to: " << i->endpoint() << std::endl;
* } @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename ConnectCondition>
Iterator connect(basic_socket<Protocol, SocketService>& s,
Iterator connect(basic_socket<Protocol, Executor>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition,
asio::error_code& ec);

@@ -598,8 +599,8 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
/**
* @defgroup async_connect asio::async_connect
*
* @brief Asynchronously establishes a socket connection by trying each
* endpoint in a sequence.
* @brief The @c async_connect function is a composed asynchronous operation
* that establishes a socket connection by trying each endpoint in a sequence.
*/
/*@{*/

@@ -630,14 +631,14 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* const typename Protocol::endpoint& endpoint
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@@ -664,19 +665,19 @@ Iterator connect(basic_socket<Protocol, SocketService>& s,
* // ...
* } @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename EndpointSequence, typename RangeConnectHandler>
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol, SocketService>& s,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated.) Asynchronously establishes a socket connection by trying each
/// endpoint in a sequence.
/// (Deprecated: Use range overload.) Asynchronously establishes a socket
/// connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
@@ -702,20 +703,20 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol, SocketService>& s,
Iterator begin, ASIO_MOVE_ARG(IteratorConnectHandler) handler,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
#endif // !defined(ASIO_NO_DEPRECATED)

@@ -748,13 +749,13 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* @code std::vector<tcp::endpoint> endpoints = ...;
* tcp::socket s(io_context);
* tcp::socket s(my_context);
* asio::async_connect(s,
* endpoints.begin(), endpoints.end(),
* connect_handler);
@@ -768,12 +769,11 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* // ...
* } @endcode
*/
template <typename Protocol, typename SocketService,
template <typename Protocol, typename Executor,
typename Iterator, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol, SocketService>& s,
Iterator begin, Iterator end,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end,
ASIO_MOVE_ARG(IteratorConnectHandler) handler);

/// Asynchronously establishes a socket connection by trying each endpoint in a
@@ -814,9 +814,9 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* The following connect condition function object can be used to output
@@ -833,9 +833,9 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@@ -871,19 +871,19 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* }
* } @endcode
*/
template <typename Protocol, typename SocketService, typename EndpointSequence,
template <typename Protocol, typename Executor, typename EndpointSequence,
typename ConnectCondition, typename RangeConnectHandler>
ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,
void (asio::error_code, typename Protocol::endpoint))
async_connect(basic_socket<Protocol, SocketService>& s,
async_connect(basic_socket<Protocol, Executor>& s,
const EndpointSequence& endpoints, ConnectCondition connect_condition,
ASIO_MOVE_ARG(RangeConnectHandler) handler,
typename enable_if<is_endpoint_sequence<
EndpointSequence>::value>::type* = 0);

#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated.) Asynchronously establishes a socket connection by trying each
/// endpoint in a sequence.
/// (Deprecated: Use range overload.) Asynchronously establishes a socket
/// connection by trying each endpoint in a sequence.
/**
* This function attempts to connect a socket to one of a sequence of
* endpoints. It does this by repeated calls to the socket's @c async_connect
@@ -920,19 +920,19 @@ async_connect(basic_socket<Protocol, SocketService>& s,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @note This overload assumes that a default constructed object of type @c
* Iterator represents the end of the sequence. This is a valid assumption for
* iterator types such as @c asio::ip::tcp::resolver::iterator.
*/
template <typename Protocol, typename SocketService, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler,
typename enable_if<!is_endpoint_sequence<Iterator>::value>::type* = 0);
@@ -978,9 +978,9 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* Iterator iterator
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the handler will not be invoked from within this function. Invocation
* of the handler will be performed in a manner equivalent to using
* asio::io_context::post().
* not, the handler will not be invoked from within this function. On
* immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Example
* The following connect condition function object can be used to output
@@ -997,9 +997,9 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* }
* }; @endcode
* It would be used with the asio::connect function as follows:
* @code tcp::resolver r(io_context);
* @code tcp::resolver r(my_context);
* tcp::resolver::query q("host", "service");
* tcp::socket s(io_context);
* tcp::socket s(my_context);
*
* // ...
*
@@ -1036,12 +1036,12 @@ async_connect(basic_socket<Protocol, SocketService>& s, Iterator begin,
* }
* } @endcode
*/
template <typename Protocol, typename SocketService, typename Iterator,
template <typename Protocol, typename Executor, typename Iterator,
typename ConnectCondition, typename IteratorConnectHandler>
ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,
void (asio::error_code, Iterator))
async_connect(basic_socket<Protocol, SocketService>& s,
Iterator begin, Iterator end, ConnectCondition connect_condition,
async_connect(basic_socket<Protocol, Executor>& s, Iterator begin,
Iterator end, ConnectCondition connect_condition,
ASIO_MOVE_ARG(IteratorConnectHandler) handler);

/*@}*/


+ 7
- 7
source/modules/hylia/link/asio/coroutine.hpp View File

@@ -2,7 +2,7 @@
// coroutine.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -205,7 +205,7 @@ class coroutine_ref;
* {
* do
* {
* socket_.reset(new tcp::socket(io_context_));
* socket_.reset(new tcp::socket(my_context_));
* yield acceptor->async_accept(*socket_, *this);
* fork server(*this)();
* } while (is_parent());
@@ -227,7 +227,7 @@ class coroutine_ref;
* Note that @c fork doesn't do the actual forking by itself. It is the
* application's responsibility to create a clone of the coroutine and call it.
* The clone can be called immediately, as above, or scheduled for delayed
* execution using something like io_context::post().
* execution using something like asio::post().
*
* @par Alternate macro names
*
@@ -289,7 +289,7 @@ private:
bail_out_of_coroutine: \
break; \
} \
else case 0:
else /* fall-through */ case 0:

#define ASIO_CORO_YIELD_IMPL(n) \
for (_coro_value = (n);;) \
@@ -301,12 +301,12 @@ private:
else \
switch (_coro_value ? 0 : 1) \
for (;;) \
case -1: if (_coro_value) \
/* fall-through */ case -1: if (_coro_value) \
goto terminate_coroutine; \
else for (;;) \
case 1: if (_coro_value) \
/* fall-through */ case 1: if (_coro_value) \
goto bail_out_of_coroutine; \
else case 0:
else /* fall-through */ case 0:

#define ASIO_CORO_FORK_IMPL(n) \
for (_coro_value = -(n);; _coro_value = (n)) \


+ 0
- 438
source/modules/hylia/link/asio/datagram_socket_service.hpp View File

@@ -1,438 +0,0 @@
//
// datagram_socket_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_DATAGRAM_SOCKET_SERVICE_HPP
#define ASIO_DATAGRAM_SOCKET_SERVICE_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/io_context.hpp"

#if defined(ASIO_WINDOWS_RUNTIME)
# include "asio/detail/null_socket_service.hpp"
#elif defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_socket_service.hpp"
#else
# include "asio/detail/reactive_socket_service.hpp"
#endif

#include "asio/detail/push_options.hpp"

namespace asio {

/// Default service implementation for a datagram socket.
template <typename Protocol>
class datagram_socket_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_context::service
#else
: public asio::detail::service_base<datagram_socket_service<Protocol> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_context::id id;
#endif

/// The protocol type.
typedef Protocol protocol_type;

/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;

private:
// The type of the platform-specific implementation.
#if defined(ASIO_WINDOWS_RUNTIME)
typedef detail::null_socket_service<Protocol> service_impl_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_socket_service<Protocol> service_impl_type;
#else
typedef detail::reactive_socket_service<Protocol> service_impl_type;
#endif

public:
/// The type of a datagram socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif

/// The native socket type.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename service_impl_type::native_handle_type native_handle_type;
#endif

/// Construct a new datagram socket service for the specified io_context.
explicit datagram_socket_service(asio::io_context& io_context)
: asio::detail::service_base<
datagram_socket_service<Protocol> >(io_context),
service_impl_(io_context)
{
}

/// Construct a new datagram socket implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}

#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a new datagram socket implementation.
void move_construct(implementation_type& impl,
implementation_type& other_impl)
{
service_impl_.move_construct(impl, other_impl);
}

/// Move-assign from another datagram socket implementation.
void move_assign(implementation_type& impl,
datagram_socket_service& other_service,
implementation_type& other_impl)
{
service_impl_.move_assign(impl, other_service.service_impl_, other_impl);
}

/// Move-construct a new datagram socket implementation from another protocol
/// type.
template <typename Protocol1>
void converting_move_construct(implementation_type& impl,
typename datagram_socket_service<
Protocol1>::implementation_type& other_impl,
typename enable_if<is_convertible<
Protocol1, Protocol>::value>::type* = 0)
{
service_impl_.template converting_move_construct<Protocol1>(
impl, other_impl);
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)

/// Destroy a datagram socket implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}

// Open a new datagram socket implementation.
asio::error_code open(implementation_type& impl,
const protocol_type& protocol, asio::error_code& ec)
{
if (protocol.type() == ASIO_OS_DEF(SOCK_DGRAM))
service_impl_.open(impl, protocol, ec);
else
ec = asio::error::invalid_argument;
return ec;
}

/// Assign an existing native socket to a datagram socket.
asio::error_code assign(implementation_type& impl,
const protocol_type& protocol, const native_handle_type& native_socket,
asio::error_code& ec)
{
return service_impl_.assign(impl, protocol, native_socket, ec);
}

/// Determine whether the socket is open.
bool is_open(const implementation_type& impl) const
{
return service_impl_.is_open(impl);
}

/// Close a datagram socket implementation.
asio::error_code close(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.close(impl, ec);
}

/// Get the native socket implementation.
native_handle_type native_handle(implementation_type& impl)
{
return service_impl_.native_handle(impl);
}

/// Cancel all asynchronous operations associated with the socket.
asio::error_code cancel(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}

/// Determine whether the socket is at the out-of-band data mark.
bool at_mark(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.at_mark(impl, ec);
}

/// Determine the number of bytes available for reading.
std::size_t available(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.available(impl, ec);
}

// Bind the datagram socket to the specified local endpoint.
asio::error_code bind(implementation_type& impl,
const endpoint_type& endpoint, asio::error_code& ec)
{
return service_impl_.bind(impl, endpoint, ec);
}

/// Connect the datagram socket to the specified endpoint.
asio::error_code connect(implementation_type& impl,
const endpoint_type& peer_endpoint, asio::error_code& ec)
{
return service_impl_.connect(impl, peer_endpoint, ec);
}

/// Start an asynchronous connect.
template <typename ConnectHandler>
ASIO_INITFN_RESULT_TYPE(ConnectHandler,
void (asio::error_code))
async_connect(implementation_type& impl,
const endpoint_type& peer_endpoint,
ASIO_MOVE_ARG(ConnectHandler) handler)
{
async_completion<ConnectHandler,
void (asio::error_code)> init(handler);

service_impl_.async_connect(impl, peer_endpoint, init.handler);

return init.result.get();
}

/// Set a socket option.
template <typename SettableSocketOption>
asio::error_code set_option(implementation_type& impl,
const SettableSocketOption& option, asio::error_code& ec)
{
return service_impl_.set_option(impl, option, ec);
}

/// Get a socket option.
template <typename GettableSocketOption>
asio::error_code get_option(const implementation_type& impl,
GettableSocketOption& option, asio::error_code& ec) const
{
return service_impl_.get_option(impl, option, ec);
}

/// Perform an IO control command on the socket.
template <typename IoControlCommand>
asio::error_code io_control(implementation_type& impl,
IoControlCommand& command, asio::error_code& ec)
{
return service_impl_.io_control(impl, command, ec);
}

/// Gets the non-blocking mode of the socket.
bool non_blocking(const implementation_type& impl) const
{
return service_impl_.non_blocking(impl);
}

/// Sets the non-blocking mode of the socket.
asio::error_code non_blocking(implementation_type& impl,
bool mode, asio::error_code& ec)
{
return service_impl_.non_blocking(impl, mode, ec);
}

/// Gets the non-blocking mode of the native socket implementation.
bool native_non_blocking(const implementation_type& impl) const
{
return service_impl_.native_non_blocking(impl);
}

/// Sets the non-blocking mode of the native socket implementation.
asio::error_code native_non_blocking(implementation_type& impl,
bool mode, asio::error_code& ec)
{
return service_impl_.native_non_blocking(impl, mode, ec);
}

/// Get the local endpoint.
endpoint_type local_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.local_endpoint(impl, ec);
}

/// Get the remote endpoint.
endpoint_type remote_endpoint(const implementation_type& impl,
asio::error_code& ec) const
{
return service_impl_.remote_endpoint(impl, ec);
}

/// Disable sends or receives on the socket.
asio::error_code shutdown(implementation_type& impl,
socket_base::shutdown_type what, asio::error_code& ec)
{
return service_impl_.shutdown(impl, what, ec);
}

/// Wait for the socket to become ready to read, ready to write, or to have
/// pending error conditions.
asio::error_code wait(implementation_type& impl,
socket_base::wait_type w, asio::error_code& ec)
{
return service_impl_.wait(impl, w, ec);
}

/// Asynchronously wait for the socket to become ready to read, ready to
/// write, or to have pending error conditions.
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(implementation_type& impl, socket_base::wait_type w,
ASIO_MOVE_ARG(WaitHandler) handler)
{
async_completion<WaitHandler,
void (asio::error_code)> init(handler);

service_impl_.async_wait(impl, w, init.handler);

return init.result.get();
}

/// Send the given data to the peer.
template <typename ConstBufferSequence>
std::size_t send(implementation_type& impl,
const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send(impl, buffers, flags, ec);
}

/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_send(implementation_type& impl, const ConstBufferSequence& buffers,
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);

service_impl_.async_send(impl, buffers, flags, init.handler);

return init.result.get();
}

/// Send a datagram to the specified endpoint.
template <typename ConstBufferSequence>
std::size_t send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.send_to(impl, buffers, destination, flags, ec);
}

/// Start an asynchronous send.
template <typename ConstBufferSequence, typename WriteHandler>
ASIO_INITFN_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_send_to(implementation_type& impl,
const ConstBufferSequence& buffers, const endpoint_type& destination,
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteHandler) handler)
{
async_completion<WriteHandler,
void (asio::error_code, std::size_t)> init(handler);

service_impl_.async_send_to(impl, buffers,
destination, flags, init.handler);

return init.result.get();
}

/// Receive some data from the peer.
template <typename MutableBufferSequence>
std::size_t receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive(impl, buffers, flags, ec);
}

/// Start an asynchronous receive.
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_receive(implementation_type& impl,
const MutableBufferSequence& buffers,
socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);

service_impl_.async_receive(impl, buffers, flags, init.handler);

return init.result.get();
}

/// Receive a datagram with the endpoint of the sender.
template <typename MutableBufferSequence>
std::size_t receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags, asio::error_code& ec)
{
return service_impl_.receive_from(impl, buffers, sender_endpoint, flags,
ec);
}

/// Start an asynchronous receive that will get the endpoint of the sender.
template <typename MutableBufferSequence, typename ReadHandler>
ASIO_INITFN_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_receive_from(implementation_type& impl,
const MutableBufferSequence& buffers, endpoint_type& sender_endpoint,
socket_base::message_flags flags,
ASIO_MOVE_ARG(ReadHandler) handler)
{
async_completion<ReadHandler,
void (asio::error_code, std::size_t)> init(handler);

service_impl_.async_receive_from(impl, buffers,
sender_endpoint, flags, init.handler);

return init.result.get();
}

private:
// Destroy all user-defined handler objects owned by the service.
void shutdown()
{
service_impl_.shutdown();
}

// The platform-specific implementation.
service_impl_type service_impl_;
};

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_DATAGRAM_SOCKET_SERVICE_HPP

+ 1
- 1
source/modules/hylia/link/asio/deadline_timer.hpp View File

@@ -2,7 +2,7 @@
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 0
- 170
source/modules/hylia/link/asio/deadline_timer_service.hpp View File

@@ -1,170 +0,0 @@
//
// deadline_timer_service.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_DEADLINE_TIMER_SERVICE_HPP
#define ASIO_DEADLINE_TIMER_SERVICE_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"

#if defined(ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)

#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/io_context.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/timer_queue_ptime.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {

/// Default service implementation for a timer.
template <typename TimeType,
typename TimeTraits = asio::time_traits<TimeType> >
class deadline_timer_service
#if defined(GENERATING_DOCUMENTATION)
: public asio::io_context::service
#else
: public asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >
#endif
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The unique service identifier.
static asio::io_context::id id;
#endif

/// The time traits type.
typedef TimeTraits traits_type;

/// The time type.
typedef typename traits_type::time_type time_type;

/// The duration type.
typedef typename traits_type::duration_type duration_type;

private:
// The type of the platform-specific implementation.
typedef detail::deadline_timer_service<traits_type> service_impl_type;

public:
/// The implementation type of the deadline timer.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined implementation_type;
#else
typedef typename service_impl_type::implementation_type implementation_type;
#endif

/// Construct a new timer service for the specified io_context.
explicit deadline_timer_service(asio::io_context& io_context)
: asio::detail::service_base<
deadline_timer_service<TimeType, TimeTraits> >(io_context),
service_impl_(io_context)
{
}

/// Construct a new timer implementation.
void construct(implementation_type& impl)
{
service_impl_.construct(impl);
}

/// Destroy a timer implementation.
void destroy(implementation_type& impl)
{
service_impl_.destroy(impl);
}

/// Cancel any asynchronous wait operations associated with the timer.
std::size_t cancel(implementation_type& impl, asio::error_code& ec)
{
return service_impl_.cancel(impl, ec);
}

/// Cancels one asynchronous wait operation associated with the timer.
std::size_t cancel_one(implementation_type& impl,
asio::error_code& ec)
{
return service_impl_.cancel_one(impl, ec);
}

/// Get the expiry time for the timer as an absolute time.
time_type expires_at(const implementation_type& impl) const
{
return service_impl_.expiry(impl);
}

/// Set the expiry time for the timer as an absolute time.
std::size_t expires_at(implementation_type& impl,
const time_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_at(impl, expiry_time, ec);
}

/// Get the expiry time for the timer relative to now.
duration_type expires_from_now(const implementation_type& impl) const
{
return TimeTraits::subtract(service_impl_.expiry(impl), TimeTraits::now());
}

/// Set the expiry time for the timer relative to now.
std::size_t expires_from_now(implementation_type& impl,
const duration_type& expiry_time, asio::error_code& ec)
{
return service_impl_.expires_after(impl, expiry_time, ec);
}

// Perform a blocking wait on the timer.
void wait(implementation_type& impl, asio::error_code& ec)
{
service_impl_.wait(impl, ec);
}

// Start an asynchronous wait on the timer.
template <typename WaitHandler>
ASIO_INITFN_RESULT_TYPE(WaitHandler,
void (asio::error_code))
async_wait(implementation_type& impl,
ASIO_MOVE_ARG(WaitHandler) handler)
{
async_completion<WaitHandler,
void (asio::error_code)> init(handler);

service_impl_.async_wait(impl, init.handler);

return init.result.get();
}

private:
// Destroy all user-defined handler objects owned by the service.
void shutdown()
{
service_impl_.shutdown();
}

// The platform-specific implementation.
service_impl_type service_impl_;
};

} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION)

#endif // ASIO_DEADLINE_TIMER_SERVICE_HPP

+ 11
- 1
source/modules/hylia/link/asio/defer.hpp View File

@@ -2,7 +2,7 @@
// defer.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -31,6 +31,11 @@ namespace asio {
* executor. The function object is queued for execution, and is never called
* from the current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* This function has the following effects:
*
* @li Constructs a function object handler of type @c Handler, initialized
@@ -59,6 +64,11 @@ ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer(
* The function object is queued for execution, and is never called from the
* current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* This function has the following effects:
*
* @li Constructs a function object handler of type @c Handler, initialized


+ 62
- 0
source/modules/hylia/link/asio/detached.hpp View File

@@ -0,0 +1,62 @@
//
// detached.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_DETACHED_HPP
#define ASIO_DETACHED_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include <memory>

#include "asio/detail/push_options.hpp"

namespace asio {

/// Class used to specify that an asynchronous operation is detached.
/**

* The detached_t class is used to indicate that an asynchronous operation is
* detached. That is, there is no completion handler waiting for the
* operation's result. A detached_t object may be passed as a handler to an
* asynchronous operation, typically using the special value
* @c asio::detached. For example:

* @code my_socket.async_send(my_buffer, asio::detached);
* @endcode
*/
class detached_t
{
public:
/// Constructor.
ASIO_CONSTEXPR detached_t()
{
}
};

/// A special value, similar to std::nothrow.
/**
* See the documentation for asio::detached_t for a usage example.
*/
#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
constexpr detached_t detached;
#elif defined(ASIO_MSVC)
__declspec(selectany) detached_t detached;
#endif

} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/impl/detached.hpp"

#endif // ASIO_DETACHED_HPP

+ 1
- 1
source/modules/hylia/link/asio/detail/array.hpp View File

@@ -2,7 +2,7 @@
// detail/array.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 1
- 1
source/modules/hylia/link/asio/detail/array_fwd.hpp View File

@@ -2,7 +2,7 @@
// detail/array_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 1
- 1
source/modules/hylia/link/asio/detail/assert.hpp View File

@@ -2,7 +2,7 @@
// detail/assert.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 1
- 1
source/modules/hylia/link/asio/detail/atomic_count.hpp View File

@@ -2,7 +2,7 @@
// detail/atomic_count.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 4
- 3
source/modules/hylia/link/asio/detail/base_from_completion_cond.hpp View File

@@ -2,7 +2,7 @@
// detail/base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -27,8 +27,9 @@ template <typename CompletionCondition>
class base_from_completion_cond
{
protected:
explicit base_from_completion_cond(CompletionCondition completion_condition)
: completion_condition_(completion_condition)
explicit base_from_completion_cond(CompletionCondition& completion_condition)
: completion_condition_(
ASIO_MOVE_CAST(CompletionCondition)(completion_condition))
{
}



+ 358
- 1
source/modules/hylia/link/asio/detail/bind_handler.hpp View File

@@ -2,7 +2,7 @@
// detail/bind_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -223,6 +223,363 @@ inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler(
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2);
}

template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
class binder3
{
public:
template <typename T>
binder3(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3)
: handler_(ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}

binder3(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3)
: handler_(ASIO_MOVE_CAST(Handler)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}

#if defined(ASIO_HAS_MOVE)
binder3(const binder3& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_)
{
}

binder3(binder3&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_))
{
}
#endif // defined(ASIO_HAS_MOVE)

void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_));
}

void operator()() const
{
handler_(arg1_, arg2_, arg3_);
}

//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
};

template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void* asio_handler_allocate(std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline bool asio_handler_is_continuation(
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}

template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Function, typename Handler,
typename Arg1, typename Arg2, typename Arg3>
inline void asio_handler_invoke(const Function& function,
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler(
ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3)
{
return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3);
}

template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
class binder4
{
public:
template <typename T>
binder4(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}

binder4(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(ASIO_MOVE_CAST(Handler)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}

#if defined(ASIO_HAS_MOVE)
binder4(const binder4& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_),
arg4_(other.arg4_)
{
}

binder4(binder4&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_))
{
}
#endif // defined(ASIO_HAS_MOVE)

void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_));
}

void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_);
}

//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
};

template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void* asio_handler_allocate(std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}

template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}

template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline bool asio_handler_is_continuation(
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}

template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline void asio_handler_invoke(const Function& function,
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>
bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
{
return binder4<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4);
}

template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
class binder5
{
public:
template <typename T>
binder5(int, ASIO_MOVE_ARG(T) handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(ASIO_MOVE_CAST(T)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}

binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(ASIO_MOVE_CAST(Handler)(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}

#if defined(ASIO_HAS_MOVE)
binder5(const binder5& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_),
arg4_(other.arg4_),
arg5_(other.arg5_)
{
}

binder5(binder5&& other)
: handler_(ASIO_MOVE_CAST(Handler)(other.handler_)),
arg1_(ASIO_MOVE_CAST(Arg1)(other.arg1_)),
arg2_(ASIO_MOVE_CAST(Arg2)(other.arg2_)),
arg3_(ASIO_MOVE_CAST(Arg3)(other.arg3_)),
arg4_(ASIO_MOVE_CAST(Arg4)(other.arg4_)),
arg5_(ASIO_MOVE_CAST(Arg5)(other.arg5_))
{
}
#endif // defined(ASIO_HAS_MOVE)

void operator()()
{
handler_(static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_));
}

void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}

//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
Arg5 arg5_;
};

template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void* asio_handler_allocate(std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return asio_handler_alloc_helpers::allocate(
size, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_deallocate(void* pointer, std::size_t size,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_alloc_helpers::deallocate(
pointer, size, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline bool asio_handler_is_continuation(
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}

template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Function, typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4, typename Arg5>
inline void asio_handler_invoke(const Function& function,
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
asio_handler_invoke_helpers::invoke(
function, this_handler->handler_);
}

template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>
bind_handler(ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
{
return binder5<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0,
ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5);
}

#if defined(ASIO_HAS_MOVE)

template <typename Handler, typename Arg1>


+ 1
- 1
source/modules/hylia/link/asio/detail/buffer_resize_guard.hpp View File

@@ -2,7 +2,7 @@
// detail/buffer_resize_guard.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 185
- 19
source/modules/hylia/link/asio/detail/buffer_sequence_adapter.hpp View File

@@ -2,7 +2,7 @@
// detail/buffer_sequence_adapter.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -27,11 +27,12 @@ namespace detail {

class buffer_sequence_adapter_base
{
protected:
#if defined(ASIO_WINDOWS_RUNTIME)
public:
// The maximum number of buffers to support in a single operation.
enum { max_buffers = 1 };

protected:
typedef Windows::Storage::Streams::IBuffer^ native_buffer_type;

ASIO_DECL static void init_native_buffer(
@@ -42,9 +43,11 @@ protected:
native_buffer_type& buf,
const asio::const_buffer& buffer);
#elif defined(ASIO_WINDOWS) || defined(__CYGWIN__)
public:
// The maximum number of buffers to support in a single operation.
enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };

protected:
typedef WSABUF native_buffer_type;

static void init_native_buffer(WSABUF& buf,
@@ -61,9 +64,11 @@ protected:
buf.len = static_cast<ULONG>(buffer.size());
}
#else // defined(ASIO_WINDOWS) || defined(__CYGWIN__)
public:
// The maximum number of buffers to support in a single operation.
enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len };

protected:
typedef iovec native_buffer_type;

static void init_iov_base(void*& base, void* addr)
@@ -102,14 +107,9 @@ public:
explicit buffer_sequence_adapter(const Buffers& buffer_sequence)
: count_(0), total_buffer_size_(0)
{
typename Buffers::const_iterator iter = buffer_sequence.begin();
typename Buffers::const_iterator end = buffer_sequence.end();
for (; iter != end && count_ < max_buffers; ++iter, ++count_)
{
Buffer buffer(*iter);
init_native_buffer(buffers_[count_], buffer);
total_buffer_size_ += buffer.size();
}
buffer_sequence_adapter::init(
asio::buffer_sequence_begin(buffer_sequence),
asio::buffer_sequence_end(buffer_sequence));
}

native_buffer_type* buffers()
@@ -122,6 +122,11 @@ public:
return count_;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -129,8 +134,42 @@ public:

static bool all_empty(const Buffers& buffer_sequence)
{
typename Buffers::const_iterator iter = buffer_sequence.begin();
typename Buffers::const_iterator end = buffer_sequence.end();
return buffer_sequence_adapter::all_empty(
asio::buffer_sequence_begin(buffer_sequence),
asio::buffer_sequence_end(buffer_sequence));
}

static void validate(const Buffers& buffer_sequence)
{
buffer_sequence_adapter::validate(
asio::buffer_sequence_begin(buffer_sequence),
asio::buffer_sequence_end(buffer_sequence));
}

static Buffer first(const Buffers& buffer_sequence)
{
return buffer_sequence_adapter::first(
asio::buffer_sequence_begin(buffer_sequence),
asio::buffer_sequence_end(buffer_sequence));
}

private:
template <typename Iterator>
void init(Iterator begin, Iterator end)
{
Iterator iter = begin;
for (; iter != end && count_ < max_buffers; ++iter, ++count_)
{
Buffer buffer(*iter);
init_native_buffer(buffers_[count_], buffer);
total_buffer_size_ += buffer.size();
}
}

template <typename Iterator>
static bool all_empty(Iterator begin, Iterator end)
{
Iterator iter = begin;
std::size_t i = 0;
for (; iter != end && i < max_buffers; ++iter, ++i)
if (Buffer(*iter).size() > 0)
@@ -138,10 +177,10 @@ public:
return true;
}

static void validate(const Buffers& buffer_sequence)
template <typename Iterator>
static void validate(Iterator begin, Iterator end)
{
typename Buffers::const_iterator iter = buffer_sequence.begin();
typename Buffers::const_iterator end = buffer_sequence.end();
Iterator iter = begin;
for (; iter != end; ++iter)
{
Buffer buffer(*iter);
@@ -149,10 +188,10 @@ public:
}
}

static Buffer first(const Buffers& buffer_sequence)
template <typename Iterator>
static Buffer first(Iterator begin, Iterator end)
{
typename Buffers::const_iterator iter = buffer_sequence.begin();
typename Buffers::const_iterator end = buffer_sequence.end();
Iterator iter = begin;
for (; iter != end; ++iter)
{
Buffer buffer(*iter);
@@ -162,12 +201,117 @@ public:
return Buffer();
}

private:
native_buffer_type buffers_[max_buffers];
std::size_t count_;
std::size_t total_buffer_size_;
};

template <typename Buffer>
class buffer_sequence_adapter<Buffer, asio::mutable_buffer>
: buffer_sequence_adapter_base
{
public:
explicit buffer_sequence_adapter(
const asio::mutable_buffer& buffer_sequence)
{
init_native_buffer(buffer_, Buffer(buffer_sequence));
total_buffer_size_ = buffer_sequence.size();
}

native_buffer_type* buffers()
{
return &buffer_;
}

std::size_t count() const
{
return 1;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
}

static bool all_empty(const asio::mutable_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}

static void validate(const asio::mutable_buffer& buffer_sequence)
{
buffer_sequence.data();
}

static Buffer first(const asio::mutable_buffer& buffer_sequence)
{
return Buffer(buffer_sequence);
}

private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
};

template <typename Buffer>
class buffer_sequence_adapter<Buffer, asio::const_buffer>
: buffer_sequence_adapter_base
{
public:
explicit buffer_sequence_adapter(
const asio::const_buffer& buffer_sequence)
{
init_native_buffer(buffer_, Buffer(buffer_sequence));
total_buffer_size_ = buffer_sequence.size();
}

native_buffer_type* buffers()
{
return &buffer_;
}

std::size_t count() const
{
return 1;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
}

static bool all_empty(const asio::const_buffer& buffer_sequence)
{
return buffer_sequence.size() == 0;
}

static void validate(const asio::const_buffer& buffer_sequence)
{
buffer_sequence.data();
}

static Buffer first(const asio::const_buffer& buffer_sequence)
{
return Buffer(buffer_sequence);
}

private:
native_buffer_type buffer_;
std::size_t total_buffer_size_;
};

#if !defined(ASIO_NO_DEPRECATED)

template <typename Buffer>
class buffer_sequence_adapter<Buffer, asio::mutable_buffers_1>
: buffer_sequence_adapter_base
@@ -190,6 +334,11 @@ public:
return 1;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -237,6 +386,11 @@ public:
return 1;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -262,6 +416,8 @@ private:
std::size_t total_buffer_size_;
};

#endif // !defined(ASIO_NO_DEPRECATED)

template <typename Buffer, typename Elem>
class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> >
: buffer_sequence_adapter_base
@@ -285,6 +441,11 @@ public:
return 2;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;
@@ -337,6 +498,11 @@ public:
return 2;
}

std::size_t total_size() const
{
return total_buffer_size_;
}

bool all_empty() const
{
return total_buffer_size_ == 0;


+ 1
- 1
source/modules/hylia/link/asio/detail/buffered_stream_storage.hpp View File

@@ -2,7 +2,7 @@
// detail/buffered_stream_storage.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 1
- 1
source/modules/hylia/link/asio/detail/call_stack.hpp View File

@@ -2,7 +2,7 @@
// detail/call_stack.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 4
- 4
source/modules/hylia/link/asio/detail/chrono.hpp View File

@@ -2,7 +2,7 @@
// detail/chrono.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
@@ -38,11 +38,11 @@ using std::chrono::minutes;
using std::chrono::hours;
using std::chrono::time_point_cast;
#if defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
typedef std::chrono::monotonic_clock system_clock;
typedef std::chrono::monotonic_clock steady_clock;
#else // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
using std::chrono::system_clock;
#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
using std::chrono::steady_clock;
#endif // defined(ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK)
using std::chrono::system_clock;
using std::chrono::high_resolution_clock;
#elif defined(ASIO_HAS_BOOST_CHRONO)
using boost::chrono::duration;


+ 1
- 1
source/modules/hylia/link/asio/detail/chrono_time_traits.hpp View File

@@ -2,7 +2,7 @@
// detail/chrono_time_traits.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 1
- 1
source/modules/hylia/link/asio/detail/completion_handler.hpp View File

@@ -2,7 +2,7 @@
// detail/completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)


+ 94
- 0
source/modules/hylia/link/asio/detail/concurrency_hint.hpp View File

@@ -0,0 +1,94 @@
//
// detail/concurrency_hint.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_DETAIL_CONCURRENCY_HINT_HPP
#define ASIO_DETAIL_CONCURRENCY_HINT_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include "asio/detail/noncopyable.hpp"

// The concurrency hint ID and mask are used to identify when a "well-known"
// concurrency hint value has been passed to the io_context.
#define ASIO_CONCURRENCY_HINT_ID 0xA5100000u
#define ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u

// If set, this bit indicates that the scheduler should perform locking.
#define ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u

// If set, this bit indicates that the reactor should perform locking when
// managing descriptor registrations.
#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u

// If set, this bit indicates that the reactor should perform locking for I/O.
#define ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u

// Helper macro to determine if we have a special concurrency hint.
#define ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \
((static_cast<unsigned>(hint) \
& ASIO_CONCURRENCY_HINT_ID_MASK) \
== ASIO_CONCURRENCY_HINT_ID)

// Helper macro to determine if locking is enabled for a given facility.
#define ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \
(((static_cast<unsigned>(hint) \
& (ASIO_CONCURRENCY_HINT_ID_MASK \
| ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \
^ ASIO_CONCURRENCY_HINT_ID) != 0)

// This special concurrency hint disables locking in both the scheduler and
// reactor I/O. This hint has the following restrictions:
//
// - Care must be taken to ensure that all operations on the io_context and any
// of its associated I/O objects (such as sockets and timers) occur in only
// one thread at a time.
//
// - Asynchronous resolve operations fail with operation_not_supported.
//
// - If a signal_set is used with the io_context, signal_set objects cannot be
// used with any other io_context in the program.
#define ASIO_CONCURRENCY_HINT_UNSAFE \
static_cast<int>(ASIO_CONCURRENCY_HINT_ID)

// This special concurrency hint disables locking in the reactor I/O. This hint
// has the following restrictions:
//
// - Care must be taken to ensure that run functions on the io_context, and all
// operations on the io_context's associated I/O objects (such as sockets and
// timers), occur in only one thread at a time.
#define ASIO_CONCURRENCY_HINT_UNSAFE_IO \
static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
| ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
| ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION)

// The special concurrency hint provides full thread safety.
#define ASIO_CONCURRENCY_HINT_SAFE \
static_cast<int>(ASIO_CONCURRENCY_HINT_ID \
| ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \
| ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \
| ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO)

// This #define may be overridden at compile time to specify a program-wide
// default concurrency hint, used by the zero-argument io_context constructor.
#if !defined(ASIO_CONCURRENCY_HINT_DEFAULT)
# define ASIO_CONCURRENCY_HINT_DEFAULT -1
#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)

// This #define may be overridden at compile time to specify a program-wide
// concurrency hint, used by the one-argument io_context constructor when
// passed a value of 1.
#if !defined(ASIO_CONCURRENCY_HINT_1)
# define ASIO_CONCURRENCY_HINT_1 1
#endif // !defined(ASIO_CONCURRENCY_HINT_DEFAULT)

#endif // ASIO_DETAIL_CONCURRENCY_HINT_HPP

+ 112
- 0
source/modules/hylia/link/asio/detail/conditionally_enabled_event.hpp View File

@@ -0,0 +1,112 @@
//
// detail/conditionally_enabled_event.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//

#ifndef ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP
#define ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include "asio/detail/conditionally_enabled_mutex.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/null_event.hpp"
#include "asio/detail/scoped_lock.hpp"

#include "asio/detail/push_options.hpp"

namespace asio {
namespace detail {

// Mutex adapter used to conditionally enable or disable locking.
class conditionally_enabled_event
: private noncopyable
{
public:
// Constructor.
conditionally_enabled_event()
{
}

// Destructor.
~conditionally_enabled_event()
{
}

// Signal the event. (Retained for backward compatibility.)
void signal(conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.signal(lock);
}

// Signal all waiters.
void signal_all(conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.signal_all(lock);
}

// Unlock the mutex and signal one waiter.
void unlock_and_signal_one(
conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.unlock_and_signal_one(lock);
}

// If there's a waiter, unlock the mutex and signal it.
bool maybe_unlock_and_signal_one(
conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
return event_.maybe_unlock_and_signal_one(lock);
else
return false;
}

// Reset the event.
void clear(conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.clear(lock);
}

// Wait for the event to become signalled.
void wait(conditionally_enabled_mutex::scoped_lock& lock)
{
if (lock.mutex_.enabled_)
event_.wait(lock);
else
null_event().wait(lock);
}

// Timed wait for the event to become signalled.
bool wait_for_usec(
conditionally_enabled_mutex::scoped_lock& lock, long usec)
{
if (lock.mutex_.enabled_)
return event_.wait_for_usec(lock, usec);
else
return null_event().wait_for_usec(lock, usec);
}

private:
asio::detail::event event_;
};

} // namespace detail
} // namespace asio

#include "asio/detail/pop_options.hpp"

#endif // ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save