blob: df760d166738996dc153df053aff41f88e47a22f [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_GN_TAGGED_POINTER_H_
#define TOOLS_GN_TAGGED_POINTER_H_
#include "base/logging.h"
// A TaggedPointer<T.N> is a compact encoding of a (pointer, tag) pair
// when all |tag| values are guaranteed to be less than N bits long, and
// all pointer values are guaranteed to be aligned to at least N bits.
template <typename T, size_t BITS>
class TaggedPointer {
public:
TaggedPointer() = default;
TaggedPointer(T* ptr, unsigned tag)
: value_(reinterpret_cast<uintptr_t>(ptr)) {
CheckPointerValue(ptr);
CheckTagValue(tag);
value_ |= static_cast<uintptr_t>(tag);
}
T* ptr() const { return reinterpret_cast<T*>(value_ & ~kTagMask); }
unsigned tag() const { return static_cast<unsigned>(value_ & kTagMask); }
void set_ptr(T* ptr) {
CheckPointerValue(ptr);
value_ = reinterpret_cast<uintptr_t>(ptr) | (value_ & kTagMask);
}
void set_tag(unsigned tag) {
CheckTagValue(tag);
value_ = (value_ & ~kTagMask) | tag;
}
bool operator==(TaggedPointer other) const { return value_ == other.value_; }
bool operator!=(TaggedPointer other) const { return !(*this == other); }
bool operator<(TaggedPointer other) const { return value_ < other.value_; }
private:
static const uintptr_t kTagMask = (uintptr_t(1) << BITS) - 1u;
static void CheckPointerValue(T* ptr) {
DCHECK((reinterpret_cast<uintptr_t>(ptr) & kTagMask) == 0)
<< "Pointer is not aligned to " << BITS << " bits: " << ptr;
}
static void CheckTagValue(unsigned tag) {
DCHECK(tag <= kTagMask)
<< "Tag value is larger than " << BITS << " bits: " << tag;
}
uintptr_t value_ = 0;
};
#endif // TOOLS_GN_TAGGED_POINTER_H_