blob: 66ed121e22df5b2cb34aa5600a2e3b4fea15510c [file]
// Copyright 2026 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_containers/internal/intrusive_queue.h"
namespace pw::containers::internal {
auto GenericIntrusiveQueue::insert_after(Item* pos, Item& item) -> Item* {
const bool is_tail = (pos == tail_);
IntrusiveForwardListItem* inserted = list_.insert_after(pos, item);
if (is_tail) {
tail_ = inserted;
}
return static_cast<Item*>(inserted);
}
auto GenericIntrusiveQueue::erase_after(Item* pos) -> Item* {
if (pos->next_ == tail_) {
tail_ = pos;
}
return static_cast<Item*>(list_.erase_after(pos));
}
auto GenericIntrusiveQueue::erase_after(Item* first, Item* last) -> Item* {
if (last == list_.end() && first->next_ != last) {
tail_ = first;
}
return static_cast<Item*>(list_.erase_after(first, last));
}
bool GenericIntrusiveQueue::remove(const Item& item_to_remove) {
return remove_if<Item>([&item_to_remove](const Item& item) {
return &item_to_remove == &item;
}) != 0;
}
void GenericIntrusiveQueue::swap(GenericIntrusiveQueue& other) noexcept {
// This is an O(1) swap utilizing the known `tail_` elements. Standard
// `list_.swap` is O(n) for circular singly-linked lists because the pointer
// from the last item to the head must be updated.
IntrusiveForwardListItem* const before = list_.before_begin();
IntrusiveForwardListItem* const other_before = other.list_.before_begin();
if (empty()) {
if (other.empty()) {
return;
}
// If this is empty, just move the nodes from other to this.
before->next_ = other_before->next_;
other.tail_->next_ = before;
tail_ = other.tail_;
other_before->next_ = other_before;
other.tail_ = other_before;
} else if (other.empty()) {
other.swap(*this);
} else {
std::swap(before->next_, other_before->next_);
tail_->next_ = other_before;
other.tail_->next_ = before;
std::swap(tail_, other.tail_);
}
}
} // namespace pw::containers::internal