1 /*
2 Copyright (C) 2010 - 2018 by Gabriel Morin <gabrielmorin (at) gmail (dot) com>
3 Part of the Battle for Wesnoth Project https://www.wesnoth.org
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY.
11
12 See the COPYING file for more details.
13 */
14
15 /**
16 * @file
17 */
18
19 #pragma once
20
21 #include <deque>
22
23 #include <boost/multi_index/hashed_index.hpp>
24 #include <boost/multi_index/mem_fun.hpp>
25 #include <boost/multi_index/random_access_index.hpp>
26 #include <boost/multi_index_container.hpp>
27
28 #include "action.hpp"
29 #include "typedefs.hpp"
30
31 namespace wb
32 {
33
34 class move;
35
36 /**
37 * Datastructure holding the actions of a side on multiple turns.
38 *
39 * @invariant forall(t>0) if turn_size(t)==0 then turn_size(t+1)==0
40 */
41 class side_actions_container
42 {
43 public:
44
45 side_actions_container();
46
47 //! Tag for action_set's random_access index.
48 struct chronological{};
49
50 //! Tag for action_set's hashed_non_unique index.
51 struct by_unit{};
52
53 //! Tag for action_set's hashed_non_unique index.
54 struct by_hex{};
55
56 //! Underlying container
57 typedef boost::multi_index::multi_index_container <
58 action_ptr,
59 boost::multi_index::indexed_by<
60 boost::multi_index::random_access<
61 boost::multi_index::tag< chronological >>,
62 boost::multi_index::hashed_non_unique<
63 boost::multi_index::tag< by_unit >,
64 boost::multi_index::const_mem_fun< action, size_t, &action::get_unit_id >>,
65 boost::multi_index::hashed_non_unique<
66 boost::multi_index::tag< by_hex >,
67 boost::multi_index::const_mem_fun< action, map_location, &action::get_numbering_hex >>
68 >
69 > action_set;
70
71 typedef action_set::index<chronological>::type::iterator iterator;
72 typedef action_set::index<chronological>::type::const_iterator const_iterator;
73 typedef action_set::index<chronological>::type::reverse_iterator reverse_iterator;
74 typedef action_set::index<chronological>::type::const_reverse_iterator const_reverse_iterator;
75
76 typedef std::pair<iterator,iterator> range_t;
77 typedef std::pair<reverse_iterator,reverse_iterator> rrange_t;
78 typedef std::pair<const_iterator,const_iterator> crange_t;
79 typedef std::pair<const_reverse_iterator,const_reverse_iterator> crrange_t;
80
81 typedef std::deque<iterator> action_limits;
82
83
84 /**
85 * Inserts an action at the specified position.
86 *
87 * The planned turn of the inserted action is the same as the planned turn of position-1 before the insertion.
88 * If position == begin(), the new action will became the first action of the current turn.
89 *
90 * @param position The iterator before which action will be inserted.
91 * @param action The action to insert.
92 *
93 * @return The inserted action's position.
94 * @retval end() When the action can't be inserted.
95 */
96 iterator insert(iterator position, action_ptr action);
97
98 /**
99 * Queues an action to be executed last
100 * @return The queued action's position
101 * @retval end() when the action can't be inserted
102 */
103 iterator queue(size_t turn_num, action_ptr action);
104
105 /**
106 * Pushes an action in front of a given turn.
107 * @return The inserted action's position
108 */
109 iterator push_front(size_t turn, action_ptr action);
110
111 /**
112 * Moves an action earlier in the execution order.
113 * i.e. at the front of the queue by one position.
114 * @return The action's new position.
115 */
116 iterator bump_earlier(iterator position);
117
118 /**
119 * Moves an action later in the execution order.
120 * i.e. at the back of the queue by one position.
121 * @return The action's new position.
122 */
123 iterator bump_later(iterator position);
124
125 /**
126 * Deletes the action at the specified position.
127 * @return The position of the element after the one deleted, or end() if the queue is empty.
128 */
129 iterator erase(iterator position);
130
131 /**
132 * Deletes the action at the specified position.
133 * @return last
134 */
135 iterator erase(iterator first, iterator last);
136
137 /**
138 * Empties the action queue.
139 */
clear()140 void clear() { actions_.clear(); turn_beginnings_.clear(); }
141
142 /**
143 * Shift turn.
144 *
145 * The turn 0 is deleted, the actions of turn n are moved to turn n-1.
146 * @pre turn_size(0)==0
147 */
turn_shift()148 void turn_shift() { assert(turn_size(0)==0); turn_beginnings_.pop_front(); }
149
150 /**
151 * Replaces the action at a given position with another action.
152 */
replace(iterator it,action_ptr act)153 bool replace(iterator it, action_ptr act){ return actions_.replace(it, act); }
154
155
156 /**
157 * Returns a given index.
158 */
159 template <typename T>
get()160 typename action_set::index<T>::type& get(){ return actions_.get<T>(); }
161 template <typename T>
get() const162 typename action_set::index<T>::type const& get() const { return actions_.get<T>(); }
163
164 /**
165 * Projects an iterator on a given index.
166 */
167 template <typename T, typename U>
project(U it)168 typename action_set::index<T>::type::iterator project(U it){ return actions_.project<T>(it); }
169 template <typename T, typename U>
project(U it) const170 typename action_set::index<T>::type::const_iterator project(U it) const { return actions_.project<T>(it); }
171
172 /**
173 * Returns the iterator for the first (executed earlier) action within the actions queue.
174 */
begin()175 iterator begin(){ return actions_.get<chronological>().begin(); }
176 /** reverse version of the above */
rbegin()177 reverse_iterator rbegin(){ return actions_.get<chronological>().rbegin(); }
178 /** const versions of the above */
begin() const179 const_iterator begin() const { return actions_.get<chronological>().cbegin(); }
180 /** const reverse versions of the above */
rbegin() const181 const_reverse_iterator rbegin() const { return actions_.get<chronological>().crbegin(); }
182
183 /**
184 * Returns the iterator for the position *after* the last executed action within the actions queue.
185 */
end()186 iterator end(){ return actions_.get<chronological>().end(); }
187 /** reverse version of the above */
rend()188 reverse_iterator rend(){ return actions_.get<chronological>().rend(); }
189 /** const versions of the above */
end() const190 const_iterator end() const { return actions_.get<chronological>().cend(); }
191 /** const reverse versions of the above */
rend() const192 const_reverse_iterator rend() const { return actions_.get<chronological>().crend(); }
193
194 /**
195 * Indicates whether the action queue is empty.
196 */
empty() const197 bool empty() const { return actions_.empty(); }
198
199 /**
200 * Returns the number of actions in the action queue.
201 */
size() const202 size_t size() const { return actions_.size(); }
203
204 /**
205 * Returns the number of turns that have plans.
206 * If the container holds only one action on turn 1 (that is turn 0 is empty),
207 * this function will still returns 2. Indeed, turn 0 has an "empty" plan.
208 *
209 * @note The current turn is counted. That is if num_turns()==0 then empty()==true.
210 */
num_turns() const211 size_t num_turns() const { return turn_beginnings_.size(); }
212
213 /**
214 * Returns the turn of a given iterator planned execution.
215 *
216 * The value returned is the difference between the planned turn and the current turn.
217 *
218 * @retval 0 If the action is planned for the current turn.
219 */
220 size_t get_turn(const_iterator it) const;
221
222 /**
223 * Returns the position of a given iterator in its turn.
224 */
225 size_t position_in_turn(const_iterator it) const;
226
227 /**
228 * Returns the iterator for the first (executed earlier) action of a given turn within the actions queue.
229 */
230 iterator turn_begin(size_t turn_num);
231 const_iterator turn_begin(size_t turn_num) const;
turn_rbegin(size_t turn_num)232 reverse_iterator turn_rbegin(size_t turn_num){ return reverse_iterator(turn_end(turn_num)); }
turn_rbegin(size_t turn_num) const233 const_reverse_iterator turn_rbegin(size_t turn_num) const { return reverse_iterator(turn_end(turn_num)); }
234
235 /*
236 * Returns the iterator for the position *after* the last executed action of a given turn within the actions queue.
237 */
turn_end(size_t turn_num)238 iterator turn_end(size_t turn_num){ return turn_begin(turn_num+1); }
turn_end(size_t turn_num) const239 const_iterator turn_end(size_t turn_num) const { return turn_begin(turn_num+1); }
turn_rend(size_t turn_num)240 reverse_iterator turn_rend(size_t turn_num){ return reverse_iterator(turn_begin(turn_num)); }
turn_rend(size_t turn_num) const241 const_reverse_iterator turn_rend(size_t turn_num) const { return reverse_iterator(turn_begin(turn_num)); }
242
243 /**
244 * Returns an iterator range corresponding to the requested turn.
245 */
iter_turn(size_t turn_num)246 range_t iter_turn(size_t turn_num){ return range_t(turn_begin(turn_num),turn_end(turn_num)); }
riter_turn(size_t turn_num)247 rrange_t riter_turn(size_t turn_num){ return rrange_t(turn_rbegin(turn_num),turn_rend(turn_num)); }
iter_turn(size_t turn_num) const248 crange_t iter_turn(size_t turn_num) const { return crange_t(turn_begin(turn_num),turn_end(turn_num)); }
riter_turn(size_t turn_num) const249 crrange_t riter_turn(size_t turn_num) const { return crrange_t(turn_rbegin(turn_num),turn_rend(turn_num)); }
250
251 /** Returns the number of actions planned for turn turn_num */
turn_size(size_t turn_num) const252 size_t turn_size(size_t turn_num) const { return turn_end(turn_num) - turn_begin(turn_num); }
253
254 /** Get the underlying action container */
actions() const255 const action_set& actions() const { return actions_; }
256
257 template<typename Modifier>
modify(iterator position,Modifier mod)258 bool modify(iterator position, Modifier mod) { return actions_.modify(position, mod); }
259 private:
260 /**
261 * Binary search to find the occurring turn of the action pointed by an iterator.
262 */
263 size_t get_turn_impl(size_t begin, size_t end, const_iterator it) const;
264
265 action_set actions_;
266
267 /**
268 * Contains a list of iterator to the beginning of each turn.
269 *
270 * @invariant turn_beginnings_.front()==actions_.begin() || actions_.empty()
271 */
272 action_limits turn_beginnings_;
273 };
274
275
276 /**
277 * This internal whiteboard class holds the planned action queues for a team, and offers many
278 * utility methods to create and manipulate them.
279 * It also provides an interface to the underlying side_actions_container.
280 */
281 class side_actions: public std::enable_shared_from_this<side_actions>
282 {
283 public:
284 typedef side_actions_container container;
285
286 typedef container::iterator iterator;
287 typedef container::const_iterator const_iterator;
288 typedef container::reverse_iterator reverse_iterator;
289 typedef container::const_reverse_iterator const_reverse_iterator;
290
291 typedef std::pair<iterator,iterator> range_t;
292 typedef std::pair<reverse_iterator,reverse_iterator> rrange_t;
293 typedef std::pair<const_iterator,const_iterator> crange_t;
294 typedef std::pair<const_reverse_iterator,const_reverse_iterator> crrange_t;
295
296
297 side_actions();
298
299 /** Must be called only once, right after the team that owns this side_actions is added to the teams vector */
300 void set_team_index(size_t team_index);
301
302 /** Returns the team index this action queue belongs to */
team_index()303 size_t team_index() { assert(team_index_defined_); return team_index_; }
304
305 struct numbers_t;
306 /** Gets called when display is drawing a hex to determine which numbers to draw on it */
307 void get_numbers(const map_location& hex, numbers_t& result);
308
309 /**
310 * Executes the first action in the queue, and then deletes it.
311 * @return true if the action was completed successfully
312 */
313 bool execute_next();
314
315 /**
316 * Executes the specified action, if it exists in the queue.
317 * If the action is not finished, it's moved at the end of the queue.
318 * @return true if the action was completed successfully
319 */
320 bool execute(iterator position);
321
322
323 /**
324 * Indicates whether the action queue is empty.
325 */
empty() const326 bool empty() const { return actions_.empty(); }
327
328 /**
329 * Returns the number of actions in the action queue.
330 */
size() const331 size_t size() const { return actions_.size(); }
332
333 /**
334 * Returns the number of turns that have plans.
335 * If the container holds only one action on turn 1 (that is turn 0 is empty),
336 * this function will still returns 2. Indeed, turn 0 has an "empty" plan.
337 *
338 * @note The current turn is counted. That is if num_turns()==0 then empty()==true.
339 */
num_turns() const340 size_t num_turns() const { return actions_.num_turns(); }
341
342 /** Returns the number of actions planned for turn turn_num */
turn_size(size_t turn_num) const343 size_t turn_size(size_t turn_num) const { return actions_.turn_size(turn_num); }
344
345 /**
346 * Returns the turn of a given iterator planned execution.
347 *
348 * The value returned is the difference between the planned turn and the current turn.
349 *
350 * @retval 0 If the action is planned for the current turn.
351 */
get_turn(const_iterator it) const352 size_t get_turn(const_iterator it) const { return actions_.get_turn(it); }
353
354 /**
355 * Empties the action queue.
356 */
clear()357 void clear() { actions_.clear(); }
358
359 /** Sets whether or not the contents should be drawn on the screen. */
360 void hide();
361 void show();
hidden() const362 bool hidden() const {return hidden_;}
363
364 /**
365 * Inserts an action at the specified position. The begin() and end() functions might prove useful here.
366 * @return The inserted action's position.
367 */
368 iterator insert_action(iterator position, action_ptr action);
369
370 /**
371 * Queues an action to be executed last
372 * @return The queued action's position
373 */
374 iterator queue_action(size_t turn_num, action_ptr action);
375
376 /**
377 * Moves an action earlier in the execution order.
378 * i.e. at the front of the queue by one position.
379 * @return The action's new position.
380 */
381 iterator bump_earlier(iterator position, bool send_to_net = true);
382
383 /**
384 * Moves an action later in the execution order.
385 * i.e. at the back of the queue by one position.
386 * @return The action's new position.
387 */
388 iterator bump_later(iterator position, bool send_to_net = true);
389
390 /**
391 * Deletes the action at the specified position.
392 * @return The position of the element after the one deleted, or end() if the queue is empty.
393 */
394 iterator remove_action(iterator position, bool validate_after_delete = true);
395
396 /**
397 * @param action The action whose position you're looking for
398 * @return The action's position within the queue, or end() if action wasn't found.
399 */
get_position_of(action_ptr action)400 iterator get_position_of(action_ptr action){ return std::find(begin(), end(), action); }
401
402 /**
403 * Returns the iterator for the first (executed earlier) action within the actions queue.
404 */
begin()405 iterator begin(){ return actions_.begin(); }
406 /** reverse version of the above */
rbegin()407 reverse_iterator rbegin(){ return actions_.rbegin(); }
408 /** const versions of the above */
begin() const409 const_iterator begin() const { return actions_.begin(); }
rbegin() const410 const_reverse_iterator rbegin() const { return actions_.rbegin(); }
411
412 /**
413 * Returns the iterator for the position *after* the last executed action within the actions queue.
414 */
end()415 iterator end(){ return actions_.end(); }
416 /** reverse version of the above */
rend()417 reverse_iterator rend(){ return actions_.rend(); }
418 /** const versions of the above */
end() const419 const_iterator end() const { return actions_.end(); }
rend() const420 const_reverse_iterator rend() const { return actions_.rend(); }
421
turn_begin(size_t turn_num)422 iterator turn_begin(size_t turn_num){ return actions_.turn_begin(turn_num); }
turn_end(size_t turn_num)423 iterator turn_end(size_t turn_num){ return actions_.turn_end(turn_num); }
turn_rbegin(size_t turn_num)424 reverse_iterator turn_rbegin(size_t turn_num){ return actions_.turn_rbegin(turn_num); }
turn_rend(size_t turn_num)425 reverse_iterator turn_rend(size_t turn_num){ return actions_.turn_rend(turn_num); }
turn_begin(size_t turn_num) const426 const_iterator turn_begin(size_t turn_num) const { return actions_.turn_begin(turn_num); }
turn_end(size_t turn_num) const427 const_iterator turn_end(size_t turn_num) const { return actions_.turn_end(turn_num); }
turn_rbegin(size_t turn_num) const428 const_reverse_iterator turn_rbegin(size_t turn_num) const { return actions_.turn_rbegin(turn_num); }
turn_rend(size_t turn_num) const429 const_reverse_iterator turn_rend(size_t turn_num) const { return actions_.turn_rend(turn_num); }
430
431 /** Returns an iterator range corresponding to the requested turn. */
iter_turn(size_t turn_num)432 range_t iter_turn(size_t turn_num){ return actions_.iter_turn(turn_num); }
riter_turn(size_t turn_num)433 rrange_t riter_turn(size_t turn_num){ return actions_.riter_turn(turn_num); }
iter_turn(size_t turn_num) const434 crange_t iter_turn(size_t turn_num) const { return actions_.iter_turn(turn_num); }
riter_turn(size_t turn_num) const435 crrange_t riter_turn(size_t turn_num) const { return actions_.riter_turn(turn_num); }
436
437
438 /**
439 * Find the (chronologically) first action between the iterators between.first and between.second but after or equals to limit with respect to the predicate comp.
440 *
441 * This function makes sense when T is a non-chronological iterator.
442 * If T is @ref iterator and Compare is std::less<iterator>,
443 * this function returns limit if limit is in [between.first, between.second)
444 * or between.first if between.first>limit or end() otherwise.
445 *
446 * @param between the two iterators between which the action will be searched.
447 * @param limit the lower bound to search from, that is the return value `it' will verify !comp(limit, it).
448 * @param comp the predicate to compare with.
449 * @return `it' so that for all values `x' in [between.first, between.second), chronologically, !comp(x, it) and !comp(it, limit).
450 * @retval end() if no such action exist.
451 */
452 template <typename T, typename Compare>
453 iterator find_first_action_of(std::pair<T,T> between, iterator limit, Compare comp);
454 template <typename T, typename Compare>
455 const_iterator find_first_action_of(std::pair<T,T> between, const_iterator limit, Compare comp) const;
456
457 /**
458 * Find the first action occurring at a given hex.
459 *
460 * @retval end() if no action occurs at the given location.
461 */
462 iterator find_first_action_at(map_location hex);
463
464 /**
465 * Finds the first action that belongs to this unit, starting the search at the specified position.
466 * @return The position, or end() if not found.
467 */
468 iterator find_first_action_of(const unit& unit, iterator start_position);
469 iterator find_first_action_of(size_t unit_id, iterator start_position);
470 /** Variant of this method that always start searching at the beginning of the queue */
find_first_action_of(const unit & unit)471 iterator find_first_action_of(const unit& unit){ return find_first_action_of(unit, begin()); }
find_first_action_of(size_t unit_id)472 iterator find_first_action_of(size_t unit_id){ return find_first_action_of(unit_id, begin()); }
473
474 /**
475 * Finds the last action that belongs to this unit, starting the search backwards from the specified position.
476 * @return The position, or end() if not found.
477 */
478 iterator find_last_action_of(const unit& unit, iterator start_position);
479 iterator find_last_action_of(size_t unit_id, iterator start_position);
480 /** const variant of the previous function */
481 const_iterator find_last_action_of(const unit& unit, const_iterator start_position) const;
482 const_iterator find_last_action_of(size_t unit_id, iterator start_position) const;
483 /** Variant of the previous method that always start searching at the end of the queue */
484 iterator find_last_action_of(const unit& unit);
485 iterator find_last_action_of(size_t unit_id);
486 /** const variant of the previous function */
487 const_iterator find_last_action_of(const unit& unit) const;
488 const_iterator find_last_action_of(size_t unit_id) const;
489
490 bool unit_has_actions(const unit& unit);
491 size_t count_actions_of(const unit& unit);
492 std::deque<action_ptr> actions_of(const unit& unit);
493
494 /**
495 * Determines the appropriate turn number for the next action planned for this unit
496 *
497 * @warning A return value of 0 can mean that the unit has one action planned on turn 0 or that the unit doesn't have any action planned on any turn.
498 *
499 * @retval 0 if the unit doesn't have any planned action
500 */
501 size_t get_turn_num_of(const unit&) const;
502
503 /** Used to track gold spending by recruits/recalls when building the future unit map */
get_gold_spent() const504 int get_gold_spent() const { return gold_spent_; }
505 /** Used to track gold spending by recruits/recalls when building the future unit map */
506 void change_gold_spent_by(int difference);
507 /** Set gold spent back to zero */
508 void reset_gold_spent();
509 /** After a recruit action was executed the id of the unit was changed so we need to update the unitid of all following actions on that unit*/
510 void update_recruited_unit(std::size_t old_id, unit& new_unit);
511
512 void raw_turn_shift();
513 void synced_turn_shift();
514
515 /**
516 * Queues a move to be executed last
517 * @return The queued move's position
518 */
519 iterator queue_move(size_t turn_num, unit& mover, const pathfind::marked_route& route,
520 arrow_ptr arrow, fake_unit_ptr fake_unit);
521
522 /**
523 * Queues an attack or attack-move to be executed last
524 * @return The queued attack's position
525 */
526 iterator queue_attack(size_t turn_num, unit& mover, const map_location& target_hex, int weapon_choice, const pathfind::marked_route& route,
527 arrow_ptr arrow, fake_unit_ptr fake_unit);
528
529 /**
530 * Queues a recruit to be executed last
531 * @return The queued recruit's position
532 */
533 iterator queue_recruit(size_t turn_num, const std::string& unit_name, const map_location& recruit_hex);
534
535 /**
536 * Queues a recall to be executed last
537 * @return The queued recall's position
538 */
539 iterator queue_recall(size_t turn_num, const unit& unit, const map_location& recall_hex);
540
541 /**
542 * Queues a suppose_dead to be executed last
543 * @return The queued suppose_dead's position (an iterator to it)
544 */
545 iterator queue_suppose_dead(size_t turn_num, unit& curr_unit, const map_location& loc);
546
547 /**
548 * Network code. A net_cmd object (a config in disguise) represents a modification
549 * to a side_actions object. execute_net_cmd() translates one of these into
550 * a real modification of *this. The make_net_cmd_***() family of functions is
551 * convenient for building specific types of net_cmds.
552 */
553 typedef config net_cmd;
554 void execute_net_cmd(const net_cmd&);
555 net_cmd make_net_cmd_insert(size_t turn_num, size_t pos, action_const_ptr) const;
556 net_cmd make_net_cmd_insert(const const_iterator& pos, action_const_ptr) const;
557 net_cmd make_net_cmd_replace(const const_iterator& pos, action_const_ptr) const;
558 net_cmd make_net_cmd_remove(const const_iterator& pos) const;
559 net_cmd make_net_cmd_bump_later(const const_iterator& pos) const;
560 net_cmd make_net_cmd_clear() const;
561 net_cmd make_net_cmd_refresh() const;
562
563 private:
564 iterator safe_insert(size_t turn_num, size_t pos, action_ptr to_insert);
565 iterator synced_erase(iterator itor);
566 iterator synced_insert(iterator itor, action_ptr to_insert);
567 iterator synced_enqueue(size_t turn_num, action_ptr to_insert);
568 iterator safe_erase(const iterator& itor);
569
570 container actions_;
571
572 size_t team_index_;
573 bool team_index_defined_;
574
575 /** Used to store gold "spent" in planned recruits/recalls when the future unit map is applied */
576 int gold_spent_;
577
578 bool hidden_;
579 };
580
581 /** Dumps side_actions on a stream, for debug purposes. */
582 std::ostream& operator<<(std::ostream &out, const wb::side_actions& side_actions);
583
584 struct side_actions::numbers_t
585 {
586 std::vector<int> numbers_to_draw;
587 std::vector<size_t> team_numbers;
588 int main_number;
589 std::set<size_t> secondary_numbers;
590
numbers_twb::side_actions::numbers_t591 numbers_t()
592 : numbers_to_draw()
593 , team_numbers()
594 , main_number(-1)
595 , secondary_numbers()
596 {}
597 };
598
599 template <typename T, typename Compare>
find_first_action_of(std::pair<T,T> between,iterator limit,Compare comp)600 side_actions::iterator side_actions::find_first_action_of(std::pair<T,T> between, iterator limit, Compare comp)
601 {
602 iterator first = actions_.end();
603 for(T it = between.first; it != between.second; ++it) {
604 iterator chrono_it = actions_.project<container::chronological>(it);
605 if((comp(chrono_it, first) || first==actions_.end()) && !comp(chrono_it, limit)) {
606 first = chrono_it;
607 }
608 }
609 return first;
610 }
611
612 template <typename T, typename Compare>
find_first_action_of(std::pair<T,T> between,const_iterator limit,Compare comp) const613 side_actions::const_iterator side_actions::find_first_action_of(std::pair<T,T> between, const_iterator limit, Compare comp) const
614 {
615 const_iterator first = actions_.end();
616 for(T it = between.first; it != between.second; ++it) {
617 const_iterator chrono_it = actions_.project<container::chronological>(it);
618 if((comp(chrono_it, first) || first==actions_.end()) && !comp(chrono_it, limit)) {
619 first = chrono_it;
620 }
621 }
622 return first;
623 }
624
625 } //end namespace wb
626