#ifndef UI_GFX_RANGE_RANGE_H_
#define UI_GFX_RANGE_RANGE_H_
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <iosfwd>
#include <limits>
#include <string>
#include <vector>
#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "ui/gfx/range/gfx_range_export.h"
#if BUILDFLAG(IS_APPLE)
#if __OBJC__
#import <Foundation/Foundation.h>
#else
typedef struct _NSRange NSRange;
#endif
#endif
namespace gfx {
class GFX_RANGE_EXPORT Range {
public:
constexpr Range() : Range(0) {}
constexpr Range(size_t start, size_t end)
: start_(base::checked_cast<uint32_t>(start)),
end_(base::checked_cast<uint32_t>(end)) {}
constexpr explicit Range(size_t position) : Range(position, position) {}
#if BUILDFLAG(IS_APPLE)
explicit Range(const NSRange& range);
static Range FromPossiblyInvalidNSRange(const NSRange& range);
#endif
static constexpr Range InvalidRange() {
return Range(std::numeric_limits<uint32_t>::max());
}
constexpr bool IsValid() const { return *this != InvalidRange(); }
Range& MatchDirection(const Range& other) {
if (is_reversed() != other.is_reversed()) {
std::swap(start_, end_);
}
return *this;
}
constexpr size_t start() const { return start_; }
void set_start(size_t start) { start_ = base::checked_cast<uint32_t>(start); }
constexpr size_t end() const { return end_; }
void set_end(size_t end) { end_ = base::checked_cast<uint32_t>(end); }
constexpr size_t length() const { return GetMax() - GetMin(); }
constexpr bool is_reversed() const { return start() > end(); }
constexpr bool is_empty() const { return start() == end(); }
constexpr size_t GetMin() const {
return start() < end() ? start() : end();
}
constexpr size_t GetMax() const {
return start() > end() ? start() : end();
}
constexpr bool operator==(const Range& other) const = default;
constexpr auto operator<=>(const Range& other) const = default;
constexpr bool EqualsIgnoringDirection(const Range& other) const {
return GetMin() == other.GetMin() && GetMax() == other.GetMax();
}
constexpr bool Intersects(const Range& range) const {
return Intersect(range).IsValid();
}
constexpr bool Contains(const Range& range) const {
return range.IsBoundedBy(*this) &&
(range.GetMax() != GetMax() || range.is_empty() == is_empty());
}
constexpr bool IsBoundedBy(const Range& range) const {
return IsValid() && range.IsValid() && GetMin() >= range.GetMin() &&
GetMax() <= range.GetMax();
}
constexpr Range Intersect(const Range& range) const {
const size_t min = std::max(GetMin(), range.GetMin());
const size_t max = std::min(GetMax(), range.GetMax());
return (min < max || Contains(range) || range.Contains(*this))
? Range(min, max)
: InvalidRange();
}
#if BUILDFLAG(IS_APPLE)
Range& operator=(const NSRange& range);
NSRange ToNSRange() const;
#endif
std::string ToString() const;
std::vector<int> ToIntVector() const;
private:
uint32_t start_;
uint32_t end_;
};
GFX_RANGE_EXPORT std::ostream& operator<<(std::ostream& os, const Range& range);
}
#endif