From 771f447d9958031296115a84ca9fdd48d52ce95a Mon Sep 17 00:00:00 2001 From: Yuya Nishihara Date: Mon, 11 Dec 2023 21:03:04 +0900 Subject: [PATCH] index: split IndexEntry and related types to "entry" module Added pub(super) or pub where needed. I won't implement accessor methods on IndexPositionByGeneration and IndexPosition as they are purely value types, and protecting the inner values wouldn't make sense. --- lib/src/default_index/composite.rs | 3 +- lib/src/default_index/entry.rs | 143 +++++++++++++++++++++++++++++ lib/src/default_index/mod.rs | 128 +------------------------- lib/src/default_index/mutable.rs | 3 +- lib/src/default_index/readonly.rs | 3 +- lib/src/default_index/rev_walk.rs | 2 +- 6 files changed, 154 insertions(+), 128 deletions(-) create mode 100644 lib/src/default_index/entry.rs diff --git a/lib/src/default_index/composite.rs b/lib/src/default_index/composite.rs index 13c3a2f21..9f038c242 100644 --- a/lib/src/default_index/composite.rs +++ b/lib/src/default_index/composite.rs @@ -21,9 +21,10 @@ use std::sync::Arc; use itertools::Itertools; +use super::entry::{IndexEntry, IndexPosition, IndexPositionByGeneration}; use super::readonly::ReadonlyIndexSegment; use super::rev_walk::RevWalk; -use super::{IndexEntry, IndexPosition, IndexPositionByGeneration, IndexSegment}; +use super::IndexSegment; use crate::backend::{CommitId, ObjectId}; use crate::index::{HexPrefix, Index, PrefixResolution}; use crate::revset::{ResolvedExpression, Revset, RevsetEvaluationError}; diff --git a/lib/src/default_index/entry.rs b/lib/src/default_index/entry.rs new file mode 100644 index 000000000..888574f7f --- /dev/null +++ b/lib/src/default_index/entry.rs @@ -0,0 +1,143 @@ +// Copyright 2023 The Jujutsu Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#![allow(missing_docs)] + +use std::cmp::Ordering; +use std::fmt::{Debug, Formatter}; +use std::hash::{Hash, Hasher}; + +use smallvec::SmallVec; + +use super::composite::CompositeIndex; +use super::IndexSegment; +use crate::backend::{ChangeId, CommitId, ObjectId}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub struct IndexPosition(pub(super) u32); + +impl IndexPosition { + pub const MAX: Self = IndexPosition(u32::MAX); +} + +// SmallVec reuses two pointer-size fields as inline area, which meas we can +// inline up to 16 bytes (on 64-bit platform) for free. +pub(super) type SmallIndexPositionsVec = SmallVec<[IndexPosition; 4]>; + +#[derive(Clone)] +pub struct IndexEntry<'a> { + pub(super) source: &'a dyn IndexSegment, + pub(super) pos: IndexPosition, + // Position within the source segment + pub(super) local_pos: u32, +} + +impl Debug for IndexEntry<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("IndexEntry") + .field("pos", &self.pos) + .field("local_pos", &self.local_pos) + .field("commit_id", &self.commit_id().hex()) + .finish() + } +} + +impl PartialEq for IndexEntry<'_> { + fn eq(&self, other: &Self) -> bool { + self.pos == other.pos + } +} + +impl Eq for IndexEntry<'_> {} + +impl Hash for IndexEntry<'_> { + fn hash(&self, state: &mut H) { + self.pos.hash(state) + } +} + +impl<'a> IndexEntry<'a> { + pub fn position(&self) -> IndexPosition { + self.pos + } + + pub fn generation_number(&self) -> u32 { + self.source.segment_generation_number(self.local_pos) + } + + pub fn commit_id(&self) -> CommitId { + self.source.segment_commit_id(self.local_pos) + } + + pub fn change_id(&self) -> ChangeId { + self.source.segment_change_id(self.local_pos) + } + + pub fn num_parents(&self) -> u32 { + self.source.segment_num_parents(self.local_pos) + } + + pub fn parent_positions(&self) -> SmallIndexPositionsVec { + self.source.segment_parent_positions(self.local_pos) + } + + pub fn parents(&self) -> impl ExactSizeIterator> { + let composite = CompositeIndex::new(self.source); + self.parent_positions() + .into_iter() + .map(move |pos| composite.entry_by_pos(pos)) + } +} + +#[derive(Clone, Eq, PartialEq)] +pub struct IndexEntryByPosition<'a>(pub IndexEntry<'a>); + +impl Ord for IndexEntryByPosition<'_> { + fn cmp(&self, other: &Self) -> Ordering { + self.0.pos.cmp(&other.0.pos) + } +} + +impl PartialOrd for IndexEntryByPosition<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Wrapper to sort `IndexPosition` by its generation number. +/// +/// This is similar to `IndexEntry` newtypes, but optimized for size and cache +/// locality. The original `IndexEntry` will have to be looked up when needed. +#[derive(Clone, Copy, Debug, Ord, PartialOrd)] +pub(super) struct IndexPositionByGeneration { + pub generation: u32, // order by generation number + pub pos: IndexPosition, // tie breaker +} + +impl Eq for IndexPositionByGeneration {} + +impl PartialEq for IndexPositionByGeneration { + fn eq(&self, other: &Self) -> bool { + self.pos == other.pos + } +} + +impl From<&IndexEntry<'_>> for IndexPositionByGeneration { + fn from(entry: &IndexEntry<'_>) -> Self { + IndexPositionByGeneration { + generation: entry.generation_number(), + pos: entry.position(), + } + } +} diff --git a/lib/src/default_index/mod.rs b/lib/src/default_index/mod.rs index f8a4de6ae..a3e762cdc 100644 --- a/lib/src/default_index/mod.rs +++ b/lib/src/default_index/mod.rs @@ -15,19 +15,17 @@ #![allow(missing_docs)] mod composite; +mod entry; mod mutable; mod readonly; mod rev_walk; mod store; -use std::cmp::Ordering; -use std::fmt::{Debug, Formatter}; -use std::hash::{Hash, Hasher}; use std::sync::Arc; -use smallvec::SmallVec; - pub use self::composite::{CompositeIndex, IndexLevelStats, IndexStats}; +use self::entry::SmallIndexPositionsVec; +pub use self::entry::{IndexEntry, IndexEntryByPosition, IndexPosition}; pub use self::mutable::DefaultMutableIndex; pub use self::readonly::DefaultReadonlyIndex; use self::readonly::ReadonlyIndexSegment; @@ -35,20 +33,9 @@ pub use self::rev_walk::{ RevWalk, RevWalkDescendants, RevWalkDescendantsGenerationRange, RevWalkGenerationRange, }; pub use self::store::{DefaultIndexStore, DefaultIndexStoreError, IndexLoadError}; -use crate::backend::{ChangeId, CommitId, ObjectId}; +use crate::backend::{ChangeId, CommitId}; use crate::index::{HexPrefix, PrefixResolution}; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] -pub struct IndexPosition(u32); - -impl IndexPosition { - pub const MAX: Self = IndexPosition(u32::MAX); -} - -// SmallVec reuses two pointer-size fields as inline area, which meas we can -// inline up to 16 bytes (on 64-bit platform) for free. -type SmallIndexPositionsVec = SmallVec<[IndexPosition; 4]>; - trait IndexSegment: Send + Sync { fn segment_num_parent_commits(&self) -> u32; @@ -82,113 +69,6 @@ trait IndexSegment: Send + Sync { fn segment_entry_by_pos(&self, pos: IndexPosition, local_pos: u32) -> IndexEntry; } -#[derive(Clone, Eq, PartialEq)] -pub struct IndexEntryByPosition<'a>(pub IndexEntry<'a>); - -impl Ord for IndexEntryByPosition<'_> { - fn cmp(&self, other: &Self) -> Ordering { - self.0.pos.cmp(&other.0.pos) - } -} - -impl PartialOrd for IndexEntryByPosition<'_> { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -/// Wrapper to sort `IndexPosition` by its generation number. -/// -/// This is similar to `IndexEntry` newtypes, but optimized for size and cache -/// locality. The original `IndexEntry` will have to be looked up when needed. -#[derive(Clone, Copy, Debug, Ord, PartialOrd)] -struct IndexPositionByGeneration { - generation: u32, // order by generation number - pos: IndexPosition, // tie breaker -} - -impl Eq for IndexPositionByGeneration {} - -impl PartialEq for IndexPositionByGeneration { - fn eq(&self, other: &Self) -> bool { - self.pos == other.pos - } -} - -impl From<&IndexEntry<'_>> for IndexPositionByGeneration { - fn from(entry: &IndexEntry<'_>) -> Self { - IndexPositionByGeneration { - generation: entry.generation_number(), - pos: entry.position(), - } - } -} - -#[derive(Clone)] -pub struct IndexEntry<'a> { - source: &'a dyn IndexSegment, - pos: IndexPosition, - // Position within the source segment - local_pos: u32, -} - -impl Debug for IndexEntry<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.debug_struct("IndexEntry") - .field("pos", &self.pos) - .field("local_pos", &self.local_pos) - .field("commit_id", &self.commit_id().hex()) - .finish() - } -} - -impl PartialEq for IndexEntry<'_> { - fn eq(&self, other: &Self) -> bool { - self.pos == other.pos - } -} - -impl Eq for IndexEntry<'_> {} - -impl Hash for IndexEntry<'_> { - fn hash(&self, state: &mut H) { - self.pos.hash(state) - } -} - -impl<'a> IndexEntry<'a> { - pub fn position(&self) -> IndexPosition { - self.pos - } - - pub fn generation_number(&self) -> u32 { - self.source.segment_generation_number(self.local_pos) - } - - pub fn commit_id(&self) -> CommitId { - self.source.segment_commit_id(self.local_pos) - } - - pub fn change_id(&self) -> ChangeId { - self.source.segment_change_id(self.local_pos) - } - - pub fn num_parents(&self) -> u32 { - self.source.segment_num_parents(self.local_pos) - } - - pub fn parent_positions(&self) -> SmallIndexPositionsVec { - self.source.segment_parent_positions(self.local_pos) - } - - pub fn parents(&self) -> impl ExactSizeIterator> { - let composite = CompositeIndex::new(self.source); - self.parent_positions() - .into_iter() - .map(move |pos| composite.entry_by_pos(pos)) - } -} - #[cfg(test)] mod tests { use std::ops::Range; diff --git a/lib/src/default_index/mutable.rs b/lib/src/default_index/mutable.rs index bbb1ad96f..006a45d37 100644 --- a/lib/src/default_index/mutable.rs +++ b/lib/src/default_index/mutable.rs @@ -31,9 +31,10 @@ use smallvec::SmallVec; use tempfile::NamedTempFile; use super::composite::CompositeIndex; +use super::entry::{IndexEntry, IndexPosition, SmallIndexPositionsVec}; use super::readonly::{DefaultReadonlyIndex, ReadonlyIndexSegment}; use super::store::IndexLoadError; -use super::{IndexEntry, IndexPosition, IndexSegment, SmallIndexPositionsVec}; +use super::IndexSegment; use crate::backend::{ChangeId, CommitId, ObjectId}; use crate::commit::Commit; use crate::file_util::persist_content_addressed_temp_file; diff --git a/lib/src/default_index/readonly.rs b/lib/src/default_index/readonly.rs index 342c8f821..4679f18c2 100644 --- a/lib/src/default_index/readonly.rs +++ b/lib/src/default_index/readonly.rs @@ -26,9 +26,10 @@ use byteorder::{LittleEndian, ReadBytesExt}; use smallvec::SmallVec; use super::composite::CompositeIndex; +use super::entry::{IndexEntry, IndexPosition, SmallIndexPositionsVec}; use super::mutable::DefaultMutableIndex; use super::store::IndexLoadError; -use super::{IndexEntry, IndexPosition, IndexSegment, SmallIndexPositionsVec}; +use super::IndexSegment; use crate::backend::{ChangeId, CommitId, ObjectId}; use crate::index::{HexPrefix, Index, MutableIndex, PrefixResolution, ReadonlyIndex}; use crate::revset::{ResolvedExpression, Revset, RevsetEvaluationError}; diff --git a/lib/src/default_index/rev_walk.rs b/lib/src/default_index/rev_walk.rs index 1c12939a7..77723f92c 100644 --- a/lib/src/default_index/rev_walk.rs +++ b/lib/src/default_index/rev_walk.rs @@ -22,7 +22,7 @@ use std::ops::Range; use smallvec::SmallVec; use super::composite::CompositeIndex; -use super::{IndexEntry, IndexPosition, SmallIndexPositionsVec}; +use super::entry::{IndexEntry, IndexPosition, SmallIndexPositionsVec}; trait RevWalkIndex<'a> { type Position: Copy + Ord;