/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * 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
 *
 *      http://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.
 */

#ifndef INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
#define INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_

#include <cstddef>
#include <cstdint>
#include <functional>

#include "perfetto/base/logging.h"

// An intrusive tree implementation, inspired from BSD kernel's tree.h
// Unlike std::set<>, the nodes being inserted into the tree need to explicitly
// declare a RBNode structure (one for each tree they are part of).
// The user must specify a TreeTraits for each tree the struct is part of.
// The traits struct defines the type of the key and how to get to the node
// entry from the outer object.
// Usage example:
// class Person {
//  public:
//   struct Traits {
//     using KeyType = std::string;
//     static const KeyType& GetKey(const Person& p) { return p->unique_id; }
//     static constexpr size_t NodeOffset() { return offsetof(Person, node); }
//   };
//   std::string unique_id;
//   std::string name;
//   std::string surname;
//   IntrusiveTreeNode node{};
// }
//  IntrusiveTree<Person, Person::Traits> tree;
//  tree.insert(&person1);
//  ...

namespace perfetto::base {

namespace internal {

enum RBColor : uint8_t {
  BLACK = 0,
  RED = 1,
};

struct RBNode {
  RBNode* left = nullptr;
  RBNode* right = nullptr;
  RBNode* parent = nullptr;
  RBColor color = RBColor::BLACK;
};

void RBInsertColor(RBNode** root, RBNode* elm);
void RBRemove(RBNode** root, RBNode* elm);

// Returns nullptr after reaching the last leaf (the max element).
const RBNode* RBNext(const RBNode* node);

// KeyCompare tries first to use the CompareKey function in Traits, if present.
// The signature of that function is int(const KeyType&, const KeyType&).
// If the comparator function doesn't exist, falls backk on std::less<KeyType>.
template <
    class Traits,
    class = std::enable_if_t<std::is_function_v<typename Traits::CompareKey>,
                             void> >
int KeyCompare(const typename Traits::KeyType& k1,
               const typename Traits::KeyType& k2) {
  return Traits::CompareKey(k1, k2);
}

// SFINAE fallback on std::less<KeyType>
template <class Traits>
int KeyCompare(const typename Traits::KeyType& k1,
               const typename Traits::KeyType& k2) {
  std::less<typename Traits::KeyType> less_cmp;
  return less_cmp(k1, k2) ? -1 : (less_cmp(k2, k1) ? 1 : 0);
}

}  // namespace internal

using IntrusiveTreeNode = internal::RBNode;

// T is the class that has one or more IntrusiveTreeNode as fiels.
// Traits defines the key type, getter and offset between node and T.
// Traits is separate to allow the same T to be part of different trees (which
// necessitate a different Traits, at very least for the offset).
template <typename T, typename Traits>
class IntrusiveTree {
 public:
  using Key = typename Traits::KeyType;

  class Iterator {
   public:
    Iterator() = default;
    explicit Iterator(const internal::RBNode* node) : node_(node) {}
    ~Iterator() = default;
    Iterator(const Iterator&) = default;
    Iterator& operator=(const Iterator&) = default;
    Iterator(Iterator&&) noexcept = default;
    Iterator& operator=(Iterator&&) noexcept = default;

    bool operator==(const Iterator& o) const { return node_ == o.node_; }
    bool operator!=(const Iterator& o) const { return !(*this == o); }
    const T* operator->() const { return entryof(node_); }
    const T& operator*() const {
      PERFETTO_DCHECK(node_ != nullptr);
      return *operator->();
    }
    T* operator->() { return const_cast<T*>(entryof(node_)); }
    T& operator*() {
      PERFETTO_DCHECK(node_ != nullptr);
      return *operator->();
    }
    explicit operator bool() const { return node_ != nullptr; }

    Iterator& operator++() {
      node_ = internal::RBNext(node_);
      return *this;
    }

   private:
    const internal::RBNode* node_ = nullptr;
  };  // Iterator

  using value_type = T;
  using const_pointer = const T*;
  using const_iterator = Iterator;

  std::pair<Iterator, bool> Insert(T& entry) {
    // The insertion preamble is inlined because it's few instructions and
    // out-lining it would require std::function indirections for getting the
    // key and the comparator.
    int comp = 0;
    internal::RBNode* tmp = root_;
    internal::RBNode* parent = nullptr;
    internal::RBNode* const entry_node = nodeof(&entry);
    while (tmp) {
      parent = tmp;
      comp = key_compare(entry_node, parent);
      if (comp < 0) {
        tmp = tmp->left;
      } else if (comp > 0) {
        tmp = tmp->right;
      } else {
        return {Iterator(tmp), false};  // The key exists already.
      }
    }  // while(tmp)
    entry_node->left = entry_node->right = nullptr;
    entry_node->parent = parent;
    entry_node->color = internal::RBColor::RED;
    if (parent) {
      if (comp < 0) {
        PERFETTO_DCHECK(parent->left == nullptr);
        parent->left = entry_node;
      } else {
        PERFETTO_DCHECK(parent->right == nullptr);
        parent->right = entry_node;
      }
    } else {
      root_ = entry_node;
    }
    internal::RBInsertColor(&root_, entry_node);
    ++size_;
    return {Iterator(entry_node), true};
  }

  Iterator Find(const Key& key) const {
    internal::RBNode* tmp = root_;
    while (tmp) {
      int comp =
          internal::KeyCompare<Traits>(key, Traits::GetKey(*entryof(tmp)));
      if (comp < 0) {
        tmp = tmp->left;
      } else if (comp > 0) {
        tmp = tmp->right;
      } else {
        return Iterator(tmp);
      }
    }
    return Iterator(nullptr);
  }

  bool Remove(const Key& key) {
    Iterator it = Find(key);
    if (!it)
      return false;
    internal::RBRemove(&root_, nodeof(std::addressof(*it)));
    --size_;
    return true;
  }

  Iterator Remove(T& entry) { return Remove(Iterator(nodeof(&entry))); }

  Iterator Remove(Iterator it) {
    Iterator next = it;
    ++next;
    internal::RBRemove(&root_, nodeof(std::addressof(*it)));
    --size_;
    return next;
  }

  size_t Size() const { return size_; }

  Iterator begin() const {
    const internal::RBNode* node = root_;
    while (node && node->left)
      node = node->left;
    return Iterator(node);
  }

  Iterator end() const { return Iterator(nullptr); }

 private:
  static constexpr size_t off_ = Traits::NodeOffset();
  static internal::RBNode* nodeof(T* t) {
    PERFETTO_DCHECK(t != nullptr);
    return reinterpret_cast<internal::RBNode*>(reinterpret_cast<uintptr_t>(t) +
                                               off_);
  }
  static const T* entryof(const internal::RBNode* n) {
    PERFETTO_DCHECK(n != nullptr);
    return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(n) - off_);
  }
  static int key_compare(const internal::RBNode* node_a,
                         const internal::RBNode* node_b) {
    auto* a = entryof(node_a);
    auto* b = entryof(node_b);
    return internal::KeyCompare<Traits>(Traits::GetKey(*a), Traits::GetKey(*b));
  }

  internal::RBNode* root_ = nullptr;
  size_t size_ = 0;
};

}  // namespace perfetto::base

#endif  // INCLUDE_PERFETTO_EXT_BASE_INTRUSIVE_TREE_H_
