# UNDF: UNDF-2026-000000525
# ros2-0001: ParameterEventsFilter — O(N×P) std::find on names vector inside parameter loop

## Location
`rclcpp/src/rclcpp/parameter_events_filter.cpp` lines 35–57
Repository: https://github.com/ros2/rclcpp

## Severity
**HIGH** — Called every time a parameter event arrives on a ROS2 node. With N filter names and P parameters per event type, each event dispatch is O(N×P×3). Large parameter servers (e.g. nav2, MoveIt) publish batched events with dozens of parameters.

## Complexity
- Before: O(N×P) per event type, O(3×N×P) total
- After: O(N) build + O(P) dispatch = O(N+P) total

## Defective Code

```cpp
// parameter_events_filter.cpp:34-57
if (std::find(types.begin(), types.end(), EventType::NEW) != types.end()) {
    for (auto & new_parameter : event_->new_parameters) {
        if (std::find(names.begin(), names.end(), new_parameter.name) != names.end()) {
            result_.push_back(EventPair(EventType::NEW, &new_parameter));
        }
    }
}
if (std::find(types.begin(), types.end(), EventType::CHANGED) != types.end()) {
    for (auto & changed_parameter : event_->changed_parameters) {
        if (std::find(names.begin(), names.end(), changed_parameter.name) != names.end()) {
            result_.push_back(EventPair(EventType::CHANGED, &changed_parameter));
        }
    }
}
if (std::find(types.begin(), types.end(), EventType::DELETED) != types.end()) {
    for (auto & deleted_parameter : event_->deleted_parameters) {
        if (std::find(names.begin(), names.end(), deleted_parameter.name) != names.end()) {
            result_.push_back(EventPair(EventType::DELETED, &deleted_parameter));
        }
    }
}
```

**Problem:** `std::find(names.begin(), names.end(), ...)` is O(N) linear scan inside each
inner loop over event parameters. Three independent O(N×P) blocks = O(3×N×P) total.
Also `std::find` on `types` is O(T) but T≤3 so negligible.

## Fixed Code

```cpp
// Build O(1)-lookup set from names once
std::unordered_set<std::string> names_set(names.begin(), names.end());
std::unordered_set<int> types_set;
for (auto t : types) types_set.insert(static_cast<int>(t));

if (types_set.count(static_cast<int>(EventType::NEW))) {
    for (auto & new_parameter : event_->new_parameters) {
        if (names_set.count(new_parameter.name)) {
            result_.push_back(EventPair(EventType::NEW, &new_parameter));
        }
    }
}
if (types_set.count(static_cast<int>(EventType::CHANGED))) {
    for (auto & changed_parameter : event_->changed_parameters) {
        if (names_set.count(changed_parameter.name)) {
            result_.push_back(EventPair(EventType::CHANGED, &changed_parameter));
        }
    }
}
if (types_set.count(static_cast<int>(EventType::DELETED))) {
    for (auto & deleted_parameter : event_->deleted_parameters) {
        if (names_set.count(deleted_parameter.name)) {
            result_.push_back(EventPair(EventType::DELETED, &deleted_parameter));
        }
    }
}
```

## CWE
CWE-407: Inefficient Algorithmic Complexity — O(N×P) → O(N+P)
