blob: a075f3e706c021fb460501102de09b3af169989b [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 SRC_DEVELOPER_DEBUG_SHARED_ADDRESS_RANGE_H_
#define SRC_DEVELOPER_DEBUG_SHARED_ADDRESS_RANGE_H_
#include <lib/syslog/cpp/macros.h>
#include <stdint.h>
#include <string>
#include "src/developer/debug/shared/serialization.h"
namespace debug {
// Represents a range of addresses with common operations.
//
// Since end() is one-past-the-end, we technically can't represent the last byte in the address
// space. It might be better to change this class to be (begin, size) to avoid this problem but
// that's a difficult change.
class AddressRange {
public:
constexpr AddressRange() = default;
constexpr AddressRange(uint64_t begin, uint64_t end) : begin_(begin), end_(end) {
FX_DCHECK(end_ >= begin_);
}
// Returns an address range covering the entire address space. Since our end() is one-past-the
// end, it won't technically cover the last byte.
static constexpr AddressRange Everything() {
return AddressRange(0, std::numeric_limits<uint64_t>::max());
}
constexpr uint64_t begin() const { return begin_; }
constexpr uint64_t end() const { return end_; }
constexpr uint64_t size() const { return end_ - begin_; }
constexpr bool empty() const { return end_ == begin_; }
constexpr bool InRange(uint64_t addr) const { return addr >= begin_ && addr < end_; }
// Callers need to consider the semantics they want for empty ranges.
//
// An empty range whose start and end are within this range is considered to Contain/Overlap
// this one. If you want to consider empty ranges as being unoverlapping with anything you will
// need to perform an extra check.
constexpr bool Contains(const AddressRange& other) const {
return other.begin_ >= begin_ && other.end_ <= end_;
}
constexpr bool Overlaps(const AddressRange& other) const {
return other.begin_ < end_ && other.end_ > begin_;
}
constexpr bool OverlapsOrAdjacent(const AddressRange& other) const {
return other.begin_ <= end_ && other.end_ >= begin_;
}
// Returns a new range covering both inputs (|this| and |other|). If the inputs don't touch, the
// result will also cover the in-between addresses. Use the AddressRanges class if you need to
// represent multiple discontiguous ranges. Empty ranges do not count toward a union.
[[nodiscard]] AddressRange Union(const AddressRange& other) const;
constexpr bool operator==(const AddressRange& other) const {
return begin_ == other.begin_ && end_ == other.end_;
}
constexpr bool operator!=(const AddressRange& other) const { return !operator==(other); }
// Returns a string representing this set of ranges for debugging purposes.
std::string ToString() const;
void Serialize(Serializer& ser, uint32_t ver) { ser | begin_ | end_; }
private:
uint64_t begin_ = 0;
uint64_t end_ = 0;
};
// Comparison functor for comparing the beginnings of address ranges. Secondarily sorts based on
// size.
struct AddressRangeBeginCmp {
bool operator()(const AddressRange& a, const AddressRange& b) const {
if (a.begin() == b.begin())
return a.size() < b.size();
return a.begin() < b.begin();
}
};
// Compares an address with the ending of a range. For searching for an address using lower_bound
// address in a sorted list of ranges. Using this comparator, lower_bound will find the element that
// contains the item if it exists.
struct AddressRangeEndAddrCmp {
bool operator()(const AddressRange& range, uint64_t addr) const { return range.end() < addr; }
bool operator()(uint64_t addr, const AddressRange& range) const { return addr < range.end(); }
};
// Used for putting address ranges in a set where range uniqueness is required.
struct AddressRangeEqualityCmp {
bool operator()(const AddressRange& a, const AddressRange& b) const {
if (a.begin() == b.begin())
return a.end() < b.end();
return a.begin() < b.begin();
}
};
} // namespace debug
#endif // SRC_DEVELOPER_DEBUG_SHARED_ADDRESS_RANGE_H_