1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
#include "context.h"
#include <vector>
namespace mbus {
class IDiscardHandler;
class IReplyHandler;
class Reply;
/**
* A CallStack is used to ensure that a Reply travels the inverse path
* of its Message. Each Routable has a CallStack used to track its
* path. Each stack frame contains a pointer to an IReplyHandler and a
* message Context for that handler. Note that a CallStack does not
* own any objects. Also note that the CallStack object will not be
* copied when copying a Routable, as it is not part of the object
* value. This class is intended for internal messagebus use only.
**/
class CallStack
{
private:
struct Frame {
Frame(IReplyHandler *r, IDiscardHandler * d, Context c) noexcept : replyHandler(r), discardHandler(d), ctx(c) {}
IReplyHandler *replyHandler;
IDiscardHandler *discardHandler;
Context ctx;
};
using Stack = std::vector<Frame>;
Stack _stack;
public:
CallStack(const CallStack &) = delete;
CallStack & operator = (const CallStack &) = delete;
/**
* Create a new empty CallStack.
**/
CallStack() { }
~CallStack();
/**
* Swap the content of this and the argument stack.
*
* @param dst The stack to swap content with.
**/
void swap(CallStack &dst) { _stack.swap(dst._stack); }
/**
* Discard this CallStack. This method should only be used when you are
* certain that it is safe to just throw away the stack. It has similar
* effects to stopping a thread, you need to know where it is safe to do so.
**/
void discard();
/**
* Obtain the number of frames currently on this stack.
*
* @return stack size in frames
**/
uint32_t size() const { return _stack.size(); }
/**
* Push a frame on this stack. The discard handler is an optional handler,
* and may be null.
*
* @param replyHandler The handler for the correponding reply.
* @param ctx The context to store.
* @param discardHandler The handler for discarded messages.
**/
void push(IReplyHandler &replyHandler, Context ctx, IDiscardHandler *discardHandler) {
_stack.emplace_back(&replyHandler, discardHandler, ctx);
}
void push(IReplyHandler &replyHandler, Context ctx) {
_stack.emplace_back(&replyHandler, nullptr, ctx);
}
/**
* Pop a frame from this stack. The handler part of the frame will
* be returned and the context part will be set on the given
* Reply. Invoke this method on an empty stack and terrible things
* will happen.
*
* @return the next handler on the stack
* @param reply Reply that will receive the next context
**/
IReplyHandler &pop(Reply &reply);
/** Reserve space to avoid reallocation. */
void reserve(size_t sz) { _stack.reserve(sz); }
};
} // namespace mbus
|