OnixS C++ CME MDP Premium Market Data Handler 5.11.1
Users' manual and API documentation
Loading...
Searching...
No Matches
MessageOperation.h
Go to the documentation of this file.
1// Copyright Onix Solutions Limited [OnixS]. All rights reserved.
2//
3// This software owned by Onix Solutions Limited [OnixS] and is protected by copyright law
4// and international copyright treaties.
5//
6// Access to and use of the software is governed by the terms of the applicable OnixS Software
7// Services Agreement (the Agreement) and Customer end user license agreements granting
8// a non-assignable, non-transferable and non-exclusive license to use the software
9// for it's own data processing purposes under the terms defined in the Agreement.
10//
11// Except as otherwise granted within the terms of the Agreement, copying or reproduction of any part
12// of this source code or associated reference material to any other location for further reproduction
13// or redistribution, and any amendments to this copyright notice, are expressly prohibited.
14//
15// Any reproduction or redistribution for sale or hiring of the Software not in accordance with
16// the terms of the Agreement is a violation of copyright law.
17//
18
19#pragma once
20
21#include <cassert>
22#include <cstddef>
23#include <tuple>
24#include <type_traits>
25#include <utility>
26
27#include <OnixS/CME/MDH/ABI.h>
29
31
33namespace details
34{
36 template <typename MessageType> struct EntryOperationSelector;
37 template <typename Callable> class CallableOperationFactory;
38 template <typename SourceFactory, typename CustomizationFactory> class BoundMessageOperationFactory;
40 template <std::size_t...> struct IndexSequence{};
41 template <std::size_t Size, std::size_t... Indices> struct MakeIndexSequence : MakeIndexSequence<Size - 1, Size - 1, Indices...>{};
42 template <std::size_t... Indices> struct MakeIndexSequence<0, Indices...> { using Type = IndexSequence<Indices...>; };
44
45 template <typename Operation, typename Holder, typename Arguments, std::size_t... Indices>
46 auto applyMessageOperation(Holder&& message, Arguments&& arguments, IndexSequence<Indices...>) -> decltype(
47 Operation::apply(std::forward<Holder>(message), std::get<Indices>(std::forward<Arguments>(arguments))...))
48 {
49 return Operation::apply(
50 std::forward<Holder>(message), std::get<Indices>(std::forward<Arguments>(arguments))...);
51 }
52
53 template <typename Operation, typename... Arguments>
55 {
56 public:
57 explicit MessageOperation(Arguments... arguments) : arguments_(std::move(arguments)...) {}
58
59 template <typename Holder>
60 auto apply(Holder&& message) const & -> decltype(applyMessageOperation<Operation>(
61 std::forward<Holder>(message), std::declval<const std::tuple<Arguments...>&>(),
62 typename MakeIndexSequence<sizeof...(Arguments)>::Type()))
63 {
65 std::forward<Holder>(message), arguments_, typename MakeIndexSequence<sizeof...(Arguments)>::Type());
66 }
67
68 template <typename Holder>
69 auto apply(Holder&& message) && -> decltype(applyMessageOperation<Operation>(
70 std::forward<Holder>(message), std::declval<std::tuple<Arguments...>&&>(),
71 typename MakeIndexSequence<sizeof...(Arguments)>::Type()))
72 {
74 std::forward<Holder>(message), std::move(arguments_), typename MakeIndexSequence<sizeof...(Arguments)>::Type());
75 }
76
77 private:
78 std::tuple<Arguments...> arguments_;
79 };
80
81 template <typename Operation, typename... Arguments>
83 {
85 return Result(std::forward<Arguments>(arguments)...);
86 }
87
88 template <Messaging::UpdateAction::Enum Action>
90 {
91 template <typename Holder, typename... Arguments>
92 static auto apply(Holder& message, Arguments&&... arguments) -> decltype(
94 message, std::forward<Arguments>(arguments)...))
95 {
97 message, std::forward<Arguments>(arguments)...);
98 }
99 };
100
101 template <Messaging::UpdateAction::Enum Action, typename... Arguments>
102 auto makeContextualEntryOperation(Arguments&&... arguments) -> decltype(
104 std::forward<Arguments>(arguments)...))
105 {
107 std::forward<Arguments>(arguments)...);
108 }
109
110 template <typename Factory>
112 {
113 public:
114 explicit DeferredMessageOperation(Factory factory)
115 : factory_(std::move(factory))
116 , consumed_(false)
117 {
118 }
119
122
124 std::is_nothrow_move_constructible<Factory>::value)
125 : factory_(std::move(other.factory_))
126 , consumed_(other.consumed_)
127 {
128 other.consumed_ = true;
129 }
130
148 template <typename Callable>
150 auto operator%(Callable&& callable) && -> DeferredMessageOperation<BoundMessageOperationFactory<
152
153 auto materialize() && -> decltype(std::declval<Factory&>()())
154 {
155 assert(!consumed_);
156 consumed_ = true;
157 return factory_();
158 }
159
160 Factory releaseFactory() &&
161 {
162 assert(!consumed_);
163 consumed_ = true;
164 return std::move(factory_);
165 }
166
167 private:
168 Factory factory_;
169 bool consumed_;
170 };
171
172 template <typename Factory>
175 {
177 return Result(std::forward<Factory>(factory));
178 }
179
181 {
182 template <typename Holder, typename Callable>
183 static auto apply(Holder& holder, Callable&& callable) -> decltype(
184 std::forward<Callable>(callable)(holder.message()), holder)
185 {
186 std::forward<Callable>(callable)(holder.message());
187 return holder;
188 }
189 };
190
191 template <typename Callable>
193 {
194 public:
195 template <typename Argument>
196 explicit CallableOperationFactory(Argument&& callable)
197 : callable_(std::forward<Argument>(callable))
198 {
199 }
200
201 auto operator()() -> decltype(
202 makeMessageOperation<CallableOperation>(std::declval<Callable&&>()))
203 {
204 return makeMessageOperation<CallableOperation>(std::move(callable_));
205 }
206
207 private:
208 Callable callable_;
209 };
210
211 template <typename Result>
213 {
214 public:
215 explicit OperationResultHolder(Result& result) noexcept
216 : result_(result)
217 {
218 }
219
220 Result& message() noexcept
221 {
222 return result_;
223 }
224
225 private:
226 Result& result_;
227 };
228
229 template <typename SourceOperation, typename CustomizationOperation>
231 {
232 public:
233 BoundMessageOperation(SourceOperation source, CustomizationOperation customization)
234 : source_(std::move(source))
235 , customization_(std::move(customization))
236 {
237 }
238
239 template <typename Holder>
240 auto apply(Holder& holder) const -> decltype(
241 std::declval<const CustomizationOperation&>().apply(
242 std::declval<OperationResultHolder<typename std::remove_reference<decltype(
243 std::declval<const SourceOperation&>().apply(std::declval<Holder&>()))>::type>&>()),
244 std::declval<const SourceOperation&>().apply(std::declval<Holder&>()))
245 {
246 using Result = decltype(source_.apply(holder));
247 using Value = typename std::remove_reference<Result>::type;
248
249 auto&& result = source_.apply(holder);
250 OperationResultHolder<Value> resultHolder(result);
251 customization_.apply(resultHolder);
252 return std::forward<Result>(result);
253 }
254
255 private:
256 SourceOperation source_;
257 CustomizationOperation customization_;
258 };
259
260 template <typename SourceOperation, typename CustomizationOperation>
261 BoundMessageOperation<typename std::decay<SourceOperation>::type, typename std::decay<CustomizationOperation>::type>
262 makeBoundMessageOperation(SourceOperation&& source, CustomizationOperation&& customization)
263 {
264 using Result = BoundMessageOperation<
265 typename std::decay<SourceOperation>::type,
266 typename std::decay<CustomizationOperation>::type>;
267 return Result(std::forward<SourceOperation>(source), std::forward<CustomizationOperation>(customization));
268 }
269
270 template <typename SourceFactory, typename CustomizationFactory>
272 {
273 public:
274 BoundMessageOperationFactory(SourceFactory source, CustomizationFactory customization)
275 : source_(std::move(source))
276 , customization_(std::move(customization))
277 {
278 }
279
281 std::declval<SourceFactory&>()(), std::declval<CustomizationFactory&>()()))
282 {
283 auto source = source_();
284 auto customization = customization_();
285 return makeBoundMessageOperation(std::move(source), std::move(customization));
286 }
287
288 private:
289 SourceFactory source_;
290 CustomizationFactory customization_;
291 };
292
293 template <typename Factory>
294 template <typename Callable>
298 {
301 return deferMessageOperation(BoundFactory(
302 std::move(*this).releaseFactory(), CustomizationFactory(std::forward<Callable>(callable))));
303 }
304
305 template <std::size_t Index, std::size_t Size>
307 {
308 template <typename Holder, typename Operations>
309 static void apply(Holder& holder, const Operations& operations)
310 {
311 std::get<Index>(operations).apply(holder);
313 }
314 };
315
316 template <std::size_t Size>
317 struct ApplyMessageOperations<Size, Size>
318 {
319 template <typename Holder, typename Operations>
320 static void apply(Holder&, const Operations&)
321 {
322 }
323 };
324
325 template <typename Holder, typename Operation, typename Result, typename = void>
329
330 template <typename Holder, typename Operation, typename Result>
331 struct ApplicableMessageOperationResult<Holder, Operation, Result, decltype(
332 std::declval<const typename std::decay<Operation>::type&>().apply(std::declval<Holder&>()), void())>
333 {
334 using Type = Result;
335 };
336}
337
346template <typename Holder, typename... Operations>
348{
349 template <typename, typename...> friend class MessageRecipe;
350
351public:
353 using HolderType = Holder;
354
358 explicit MessageRecipe(std::tuple<Operations...> operations)
359 : operations_(std::move(operations))
360 {
361 }
362
371 void applyTo(Holder& holder) const
372 {
373 details::ApplyMessageOperations<0, sizeof...(Operations)>::apply(holder, operations_);
374 }
375
382 Holder& operator()(Holder& holder) const
383 {
384 applyTo(holder);
385 return holder;
386 }
387
394 template <typename Operation>
395 auto append(Operation&& operation) const & -> typename details::ApplicableMessageOperationResult<
396 Holder, Operation, MessageRecipe<Holder, Operations..., typename std::decay<Operation>::type>>::Type
397 {
398 using Result = MessageRecipe<Holder, Operations..., typename std::decay<Operation>::type>;
399 return Result(std::tuple_cat(operations_, std::make_tuple(std::forward<Operation>(operation))));
400 }
401
408 template <typename Operation>
409 auto append(Operation&& operation) && -> typename details::ApplicableMessageOperationResult<
410 Holder, Operation, MessageRecipe<Holder, Operations..., typename std::decay<Operation>::type>>::Type
411 {
412 using Result = MessageRecipe<Holder, Operations..., typename std::decay<Operation>::type>;
413 return Result(std::tuple_cat(std::move(operations_), std::make_tuple(std::forward<Operation>(operation))));
414 }
415
429 template <typename Callable>
430 auto operator%(Callable&& callable) const & -> decltype(
431 std::declval<const MessageRecipe&>().append(
432 details::makeMessageOperation<details::CallableOperation>(std::forward<Callable>(callable))))
433 {
434 auto operation = details::makeMessageOperation<details::CallableOperation>(std::forward<Callable>(callable));
435 return append(std::move(operation));
436 }
437
451 template <typename Callable>
452 auto operator%(Callable&& callable) && -> decltype(
453 std::move(*this).append(
454 details::makeMessageOperation<details::CallableOperation>(std::forward<Callable>(callable))))
455 {
456 auto operation = details::makeMessageOperation<details::CallableOperation>(std::forward<Callable>(callable));
457 return std::move(*this).append(std::move(operation));
458 }
459
460private:
461 std::tuple<Operations...> operations_;
462};
463
465namespace details
466{
467 template <typename> struct IsMessageRecipe : std::false_type{};
468
469 template <typename Holder, typename... Operations>
470 struct IsMessageRecipe<MessageRecipe<Holder, Operations...>> : std::true_type{};
471
472 template <typename Holder, typename Operation>
474 {
476 return Result(std::make_tuple(std::forward<Operation>(operation)));
477 }
478}
479
490template <typename Holder, typename Factory>
491auto operator|(Holder& message, details::DeferredMessageOperation<Factory>&& deferredOperation) -> typename std::enable_if<
493 decltype(std::move(deferredOperation).materialize().apply(message), message)>::type
494{
495 auto operation = std::move(deferredOperation).materialize();
496 std::move(operation).apply(message);
497 return message;
498}
499
512template <typename Holder, typename... Operations, typename Factory>
515 details::DeferredMessageOperation<Factory>&& deferredOperation) -> decltype(
516 recipe.append(std::move(deferredOperation).materialize()))
517{
518 auto operation = std::move(deferredOperation).materialize();
519 return recipe.append(std::move(operation));
520}
521
534template <typename Holder, typename... Operations, typename Factory>
537 details::DeferredMessageOperation<Factory>&& deferredOperation) -> decltype(
538 std::move(recipe).append(std::move(deferredOperation).materialize()))
539{
540 auto operation = std::move(deferredOperation).materialize();
541 return std::move(recipe).append(std::move(operation));
542}
543
545template <typename Holder, typename Operation>
546auto operator|(Holder&, Operation&&) -> typename std::enable_if<
547 !details::IsMessageRecipe<typename std::decay<Holder>::type>::value &&
548 std::is_base_of<details::MessageOperationBase, typename std::decay<Operation>::type>::value,
549 void>::type = delete;
550
552template <typename Holder, typename... Operations, typename Operation>
553auto operator|(const MessageRecipe<Holder, Operations...>&, Operation&&) -> typename std::enable_if<
554 std::is_base_of<details::MessageOperationBase, typename std::decay<Operation>::type>::value,
555 void>::type = delete;
556
558template <typename Holder, typename... Operations, typename Operation>
559auto operator|(MessageRecipe<Holder, Operations...>&&, Operation&&) -> typename std::enable_if<
560 std::is_base_of<details::MessageOperationBase, typename std::decay<Operation>::type>::value,
561 void>::type = delete;
562
564
585#define ONIXS_CMEMDH_ENTRY(Action, ...) \
586 ONIXS_CME_MDH_TESTING_NAMESPACE::details::deferMessageOperation([&]() { \
587 return ONIXS_CME_MDH_TESTING_NAMESPACE::details::makeContextualEntryOperation< \
588 ONIXS_CMEMDH_MESSAGING_NAMESPACE::UpdateAction::Action>(__VA_ARGS__); \
589 })
#define ONIXS_CME_MDH_TESTING_NAMESPACE_END
Definition Bootstrap.h:84
#define ONIXS_CME_MDH_TESTING_NAMESPACE_BEGIN
Definition Bootstrap.h:83
#define ONIXS_CMEMDH_NODISCARD
Definition Compiler.h:165
Owns a reusable recipe for constructing a held test message.
auto append(Operation &&operation) &&-> typename details::ApplicableMessageOperationResult< Holder, Operation, MessageRecipe< Holder, Operations..., typename std::decay< Operation >::type > >::Type
Returns a recipe with one operation appended.
Holder & operator()(Holder &holder) const
Initializes and populates a holder from this recipe.
auto operator%(Callable &&callable) const &-> decltype(std::declval< const MessageRecipe & >().append(details::makeMessageOperation< details::CallableOperation >(std::forward< Callable >(callable))))
Returns a recipe with an underlying-message customization appended.
auto append(Operation &&operation) const &-> typename details::ApplicableMessageOperationResult< Holder, Operation, MessageRecipe< Holder, Operations..., typename std::decay< Operation >::type > >::Type
Returns a recipe with one operation appended.
MessageRecipe(std::tuple< Operations... > operations)
Constructs a recipe from its owned operations.
Holder HolderType
Holder type materialized by this recipe.
void applyTo(Holder &holder) const
Initializes and populates a holder from this recipe.
auto operator%(Callable &&callable) &&-> decltype(std::move(*this).append(details::makeMessageOperation< details::CallableOperation >(std::forward< Callable >(callable))))
Returns a recipe with an underlying-message customization appended.
BoundMessageOperationFactory(SourceFactory source, CustomizationFactory customization)
auto operator()() -> decltype(makeBoundMessageOperation(std::declval< SourceFactory & >()(), std::declval< CustomizationFactory & >()()))
auto apply(Holder &holder) const -> decltype(std::declval< const CustomizationOperation & >().apply(std::declval< OperationResultHolder< typename std::remove_reference< decltype(std::declval< const SourceOperation & >().apply(std::declval< Holder & >()))>::type > & >()), std::declval< const SourceOperation & >().apply(std::declval< Holder & >()))
BoundMessageOperation(SourceOperation source, CustomizationOperation customization)
auto operator()() -> decltype(makeMessageOperation< CallableOperation >(std::declval< Callable && >()))
auto operator%(Callable &&callable) &&-> DeferredMessageOperation< BoundMessageOperationFactory< Factory, CallableOperationFactory< typename std::decay< Callable >::type > > >
Binds a callable customization to this deferred operation's result.
DeferredMessageOperation(DeferredMessageOperation &&other) noexcept(std::is_nothrow_move_constructible< Factory >::value)
DeferredMessageOperation & operator=(const DeferredMessageOperation &)=delete
auto materialize() &&-> decltype(std::declval< Factory & >()())
DeferredMessageOperation(const DeferredMessageOperation &)=delete
auto apply(Holder &&message) const &-> decltype(applyMessageOperation< Operation >(std::forward< Holder >(message), std::declval< const std::tuple< Arguments... > & >(), typename MakeIndexSequence< sizeof...(Arguments)>::Type()))
auto apply(Holder &&message) &&-> decltype(applyMessageOperation< Operation >(std::forward< Holder >(message), std::declval< std::tuple< Arguments... > && >(), typename MakeIndexSequence< sizeof...(Arguments)>::Type()))
DeferredMessageOperation< typename std::decay< Factory >::type > deferMessageOperation(Factory &&factory)
auto applyMessageOperation(Holder &&message, Arguments &&arguments, IndexSequence< Indices... >) -> decltype(Operation::apply(std::forward< Holder >(message), std::get< Indices >(std::forward< Arguments >(arguments))...))
MessageRecipe< Holder, typename std::decay< Operation >::type > makeMessageRecipe(Operation &&operation)
auto makeContextualEntryOperation(Arguments &&... arguments) -> decltype(makeMessageOperation< ContextualEntryOperation< Action > >(std::forward< Arguments >(arguments)...))
MessageOperation< Operation, typename std::decay< Arguments >::type... > makeMessageOperation(Arguments &&... arguments)
BoundMessageOperation< typename std::decay< SourceOperation >::type, typename std::decay< CustomizationOperation >::type > makeBoundMessageOperation(SourceOperation &&source, CustomizationOperation &&customization)
auto operator|(Holder &message, details::DeferredMessageOperation< Factory > &&deferredOperation) -> typename std::enable_if< !details::IsMessageRecipe< typename std::decay< Holder >::type >::value, decltype(std::move(deferredOperation).materialize().apply(message), message)>::type
Materializes and applies a deferred message operation to a named holder.
STL namespace.
static void apply(Holder &holder, const Operations &operations)
static auto apply(Holder &holder, Callable &&callable) -> decltype(std::forward< Callable >(callable)(holder.message()), holder)
static auto apply(Holder &message, Arguments &&... arguments) -> decltype(EntryOperationSelector< typename std::decay< Holder >::type::MessageType >::template apply< Action >(message, std::forward< Arguments >(arguments)...))