Coverage Report

Created: 2026-09-03 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/behaviortreecpp/src/controls/reactive_sequence.cpp
Line
Count
Source
1
/* Copyright (C) 2020-2025 Davide Faconti, Eurecat -  All Rights Reserved
2
*
3
*   Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4
*   to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5
*   and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
*   The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
*
8
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9
*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10
*   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11
*/
12
13
#include "behaviortree_cpp/controls/reactive_sequence.h"
14
15
namespace BT
16
{
17
18
bool ReactiveSequence::throw_if_multiple_running = false;
19
20
void ReactiveSequence::EnableException(bool enable)
21
0
{
22
0
  ReactiveSequence::throw_if_multiple_running = enable;
23
0
}
24
25
NodeStatus ReactiveSequence::tick()
26
0
{
27
0
  bool all_skipped = true;
28
0
  if(status() == NodeStatus::IDLE)
29
0
  {
30
0
    running_child_ = -1;
31
0
  }
32
0
  setStatus(NodeStatus::RUNNING);
33
34
0
  for(size_t index = 0; index < childrenCount(); index++)
35
0
  {
36
0
    TreeNode* current_child_node = children_nodes_[index];
37
0
    const NodeStatus child_status = current_child_node->executeTick();
38
39
    // switch to RUNNING state as soon as you find an active child
40
0
    all_skipped &= (child_status == NodeStatus::SKIPPED);
41
42
0
    switch(child_status)
43
0
    {
44
0
      case NodeStatus::RUNNING: {
45
        // reset the previous children, to make sure that they are
46
        // in IDLE state the next time we tick them
47
0
        for(size_t i = 0; i < childrenCount(); i++)
48
0
        {
49
0
          if(i != index)
50
0
          {
51
0
            haltChild(i);
52
0
          }
53
0
        }
54
0
        if(running_child_ == -1)
55
0
        {
56
0
          running_child_ = int(index);
57
0
        }
58
0
        else if(throw_if_multiple_running && running_child_ != static_cast<int>(index))
59
0
        {
60
0
          throw LogicError("[ReactiveSequence]: only a single child can return RUNNING.\n"
61
0
                           "This throw can be disabled with "
62
0
                           "ReactiveSequence::EnableException(false)");
63
0
        }
64
0
        return NodeStatus::RUNNING;
65
0
      }
66
67
0
      case NodeStatus::FAILURE: {
68
0
        resetChildren();
69
0
        return NodeStatus::FAILURE;
70
0
      }
71
      // do nothing if SUCCESS
72
0
      case NodeStatus::SUCCESS:
73
0
        break;
74
75
0
      case NodeStatus::SKIPPED: {
76
        // to allow it to be skipped again, we must reset the node
77
0
        haltChild(index);
78
0
      }
79
0
      break;
80
81
0
      case NodeStatus::IDLE: {
82
0
        throw LogicError("[", name(), "]: A children should not return IDLE");
83
0
      }
84
0
    }  // end switch
85
0
  }    //end for
86
87
0
  resetChildren();
88
89
  // Skip if ALL the nodes have been skipped
90
0
  return all_skipped ? NodeStatus::SKIPPED : NodeStatus::SUCCESS;
91
0
}
92
93
void ReactiveSequence::halt()
94
419
{
95
419
  running_child_ = -1;
96
419
  ControlNode::halt();
97
419
}
98
99
}  // namespace BT