Jul 28, 2024

[C++] tag pointer

Reference:
Storing data in pointers

#include <cstddef>
#include <cstdint>
#include <iostream>


enum ListType {
  kNone,
  kReady,
  kDeleting,
};


static constexpr uintptr_t kListTypeMask = 0b11;
static constexpr uintptr_t kCleanPtrMask = ~kListTypeMask;

struct Tree;

struct Node{
  void set_list_type(ListType list_type) {
    uintptr_t t = static_cast<uintptr_t>(list_type);
    uintptr_t v = ptr_and_list_type_ & kCleanPtrMask;
    ptr_and_list_type_ = (v | t);
  }

  ListType list_type() const {
    return static_cast<ListType>(ptr_and_list_type_ & kListTypeMask);
  }

  void set_prev_next_ptr(Node** p) {
    uintptr_t t = ptr_and_list_type_ & kListTypeMask;
    uintptr_t v = reinterpret_cast<uintptr_t>(p);
    ptr_and_list_type_ = (v | t);
  }

  Node** prev_next_ptr() const {
    return reinterpret_cast<Node**>(ptr_and_list_type_ & kCleanPtrMask);
  }

  Tree* tree_ = nullptr;
  Node* parent_ = nullptr;
  Node* next_ = nullptr;
  uintptr_t ptr_and_list_type_ = 0;
};

struct Tree{
  void MarkReady(Node* p) {
    p->next_ = ready_;
    p->set_prev_next_ptr(&ready_);

    if (ready_ != nullptr) {
      ready_->set_prev_next_ptr(&p->next_);
    }

    ready_ = p;
    p->set_list_type(kReady);
  }
 
  int padding;
  Node* ready_ = nullptr;
};


int main() {
  // Print 8 since padding is type of int occupies 8 bytes.
  std::cout << "offset of ready_: " <<
    reinterpret_cast<void*>(&((Tree*)0)->ready_) << "\n";

  Tree* tree = new Tree{};
  std::cout << "tree: " << reinterpret_cast<void *>(&tree) << "\n";
  std::cout << "tree offset of ready: " <<
    reinterpret_cast<void *>(&tree->ready_) << "\n";

  Node p;
  p.tree_ = tree;
  tree->MarkReady(&p);
  std::cout << reinterpret_cast<void *>(p.prev_next_ptr()) << "\n";
}

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.