File size: 2,309 Bytes
e69b72a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | """Shared typed data structures used across STRATA modules."""
from __future__ import annotations
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class CharSpan:
"""Half-open character span in Python string coordinates."""
start: int
end: int
def __post_init__(self) -> None:
if self.start < 0:
raise ValueError(f"char span start must be non-negative, got {self.start}")
if self.end < self.start:
raise ValueError(
f"char span end must be >= start, got start={self.start}, end={self.end}"
)
@property
def length(self) -> int:
return self.end - self.start
def overlaps(self, other: "CharSpan") -> bool:
return self.start < other.end and other.start < self.end
def contains(self, other: "CharSpan") -> bool:
return self.start <= other.start and other.end <= self.end
@dataclass(frozen=True, slots=True)
class ByteSpan:
"""Half-open byte span in UTF-8 encoded coordinates."""
start: int
end: int
def __post_init__(self) -> None:
if self.start < 0:
raise ValueError(f"byte span start must be non-negative, got {self.start}")
if self.end < self.start:
raise ValueError(
f"byte span end must be >= start, got start={self.start}, end={self.end}"
)
@property
def length(self) -> int:
return self.end - self.start
def overlaps(self, other: "ByteSpan") -> bool:
return self.start < other.end and other.start < self.end
def contains(self, other: "ByteSpan") -> bool:
return self.start <= other.start and other.end <= self.end
@dataclass(frozen=True, slots=True)
class AnchoredSpan:
"""Span carrying both character and byte coordinates."""
char: CharSpan
byte: ByteSpan
@classmethod
def from_offsets(
cls,
*,
char_start: int,
char_end: int,
byte_start: int,
byte_end: int,
) -> "AnchoredSpan":
return cls(
char=CharSpan(char_start, char_end),
byte=ByteSpan(byte_start, byte_end),
)
def overlaps(self, other: "AnchoredSpan") -> bool:
return self.byte.overlaps(other.byte) and self.char.overlaps(other.char)
|