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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
use std::hash::Hash;
use std::ops::Index;
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use crate::VecX;
struct VecXList<T, const N: usize> {
data: Vec<VecX<T, N>>,
}
/// A structure representing a set of indexed `VecX`.
/// It is indexed for unique `VecX` and can efficiently handle sets of VecX in some use cases.
///
/// インデックスが付けられた`VecX`の集合を表す構造体です。
/// 一意の`VecX`に対してインデックスを持ち、ユースケースによってはVecXの集合を効率的に扱えます。
///
/// For example, when considering a set of `VecX` representing a vertex army in 3D space, this is useful when there are multiple vertices with the same coordinates.
/// This method of data management is often employed in 3D data formats.
///
/// 例えば、3D空間上の頂点軍を表す`VecX`の集合を考えた際、同じ座標を持つ頂点が複数存在する場合に有効です。
/// このデータの管理方法は、しばしば3Dデータのフォーマットに採用されています。
///
/// ```
/// use vec_x::{VecX, IndexedVecXs};
///
/// let colors: Vec<VecX<u8, 3>> = [
/// [255, 0, 0],
/// [0, 255, 0],
/// [255, 0, 0],
/// [255, 0, 0],
/// [0, 0, 255],
/// [0, 255, 0],
/// ].into_iter().map(|p| VecX::new(p)).collect::<Vec<_>>();
/// let indexed_colors = IndexedVecXs::from_vec(colors);
/// let IndexedVecXs { values, indices } = indexed_colors;
///
///
/// // インデックスされた要素の数は元データの一意な要素の数と一致する
/// assert_eq!(values.len(), 3);
/// // 元データでの出現順にインデックスが付けられている
/// assert_eq!(values[0], VecX::new([255, 0, 0]));
/// assert_eq!(values[1], VecX::new([0, 255, 0]));
/// assert_eq!(values[2], VecX::new([0, 0, 255]));
///
/// // indicesの要素数は元データの要素数と一致する
/// assert_eq!(indices.len(), 6);
/// // 同じ要素は同じインデックスを持つ
/// assert_eq!(indices, vec![0, 1, 0, 0, 2, 1]);
/// ```
///
/// Also, `IndexedVecXs` implements `Index` traits, allowing access to elements using indexes.
///
/// また、`IndexedVecXs`は`Index`トレイトを実装しており、インデックスを使用して要素にアクセスできます。
///
/// ```
/// use vec_x::{VecX, IndexedVecXs};
///
/// let colors: Vec<VecX<u8, 3>> = [
/// [255, 0, 0],
/// [0, 255, 0],
/// ].into_iter().map(|p| VecX::new(p)).collect::<Vec<_>>();
///
/// let indexed_colors = IndexedVecXs::from_vec(colors);
///
/// assert_eq!(indexed_colors[0], VecX::new([255, 0, 0]));
/// assert_eq!(indexed_colors[1], VecX::new([0, 255, 0]));
/// ```
///
/// Elements of `VecX` must implement `PartialEq`,`Eq`,`Hash`.
/// This is because we use HashSet internally.
/// The Rust standard floating-point types do not implement `Eq`,`Hash` (due to NaN having multiple binary representations), so you cannot use `f32` or `f64`.
///
/// `VecX`の要素は`PartialEq`,`Eq`,`Hash`を実装している必要があります。
/// これは内部でHashSetを使用しているためです。
/// Rust標準の浮動小数点数型は`Eq`,`Hash`を実装していない(NaNが複数のバイナリ表現を持つことに起因する)ため、`f32`や`f64`を使用することはできません。
///
/// If you want to handle floating point numbers, consider using [ordered-float crates](https://crates.io/crates/ordered-float).
///
/// もし浮動小数点数を扱いたい場合、[ordered-floatクレート](https://crates.io/crates/ordered-float)を使用することを検討してください。
///
/// ```compile_fail
/// use vec_x::{VecX, IndexedVecXs};
///
/// let points: Vec<VecX<f64, 3>> = [
/// [0., 0., 0.],
/// [1., 0., 0.],
/// ].into_iter().map(|p| VecX::new(p)).collect::<Vec<_>>();
///
/// let indexed_colors = IndexedVecXs::from_vec(points); // compile error
/// ```
pub struct IndexedVecXs<T: PartialEq + Eq + Hash, const N: usize> {
/// unique set of `VecX
///
/// 一意な`VecX`の集合
pub values: IndexSet<VecX<T, N>, FxBuildHasher>,
/// Index referring to `values`.
///
/// `values`を参照するインデックス
pub indices: Vec<usize>,
}
impl<T: PartialEq + Eq + Hash, const N: usize> IndexedVecXs<T, N> {
/// This is not normally used. Use `from_vec` to generate `IndexedVecXs` from `Vec<VecX<T, N>>`.
///
/// これは通常使用されません。`Vec<VecX<T, N>>`から`IndexedVecXs`を生成するためには`from_vec`を使用してください。
pub fn new(
values: IndexSet<VecX<T, N>, FxBuildHasher>,
indices: Vec<usize>) -> Self {
Self {
values,
indices,
}
}
/// Generate empty `IndexedVecXs`.
///
/// 空の`IndexedVecXs`を生成します。
pub fn empty() -> Self {
Self {
values: IndexSet::<VecX<T, N>, FxBuildHasher>::default(),
indices: Vec::new(),
}
}
/// Returns an iterable structure `IndexedVecXIter`.
/// Internally, each time the iterator is consumed, it searches for the corresponding `VecX` from the `values` for the index in the `indices`.
///
/// イテレーション可能な構造体`IndexedVecXIter`を返します。
/// 内部的には、イテレータが消費されるたびに`values`から`indices`中のインデックスに対応する`VecX`を検索しています。
pub fn iter(&self) -> Vec<&VecX<T, N>> {
self.indices.iter().map(|i| self.values.get_index(*i).unwrap()).collect::<Vec<_>>()
}
/// Generate `IndexedVecXs` from `Vec<VecX<T, N>>`.
///
/// `Vec<VecX<T, N>>`から`IndexedVecXs`を生成します。
pub fn from_vec(vec: Vec<VecX<T, N>>) -> Self {
let mut values = IndexSet::<VecX<T, N>, FxBuildHasher>::with_capacity_and_hasher(vec.len(), FxBuildHasher::default());
let indices = vec.into_iter().map(|value| values.insert_full(value).0).collect();
Self {
values,
indices,
}
}
/// Generate Vec<&VecX<T, N>> from `IndexedVecXs`.
///
/// `IndexedVecXs`からVec<&VecX<T, N>>を生成します。
pub fn to_ref_vec(&self) -> Vec<&VecX<T, N>> {
self.indices.iter().map(|i| self.values.get_index(*i).unwrap()).collect::<Vec<_>>()
}
}
impl<T: PartialEq + Eq + Hash + Copy, const N: usize> IndexedVecXs<T, N> {
/// Convert `IndexedVecXs` to `Vec<VecX<T, N>`.
///
/// `IndexedVecXs`を`Vec<VecX<T, N>>`に変換します。
pub fn to_vec(self) -> Vec<VecX<T, N>> {
self.indices.into_iter().map(|i| *self.values.get_index(i).unwrap()).collect::<Vec<_>>()
}
}
impl<T: PartialEq + Eq + Hash, const N: usize> Index<usize> for IndexedVecXs<T, N> {
type Output = VecX<T, N>;
fn index(&self, index: usize) -> &Self::Output {
let i = self.indices.get(index).unwrap();
self.values.get_index(*i).unwrap()
}
}
/// Iterator for `IndexedVecXs`.
/// Returns the elements of `IndexedVecXs` in order.
///
/// `IndexedVecXs`のイテレータです。
/// `IndexedVecXs`の要素を順番に返します。
pub struct IndexedVecXIter<'a, T: PartialEq + Eq + Hash, const N: usize> {
collection: &'a IndexedVecXs<T, N>,
current_index: usize,
}
impl<'a, T: PartialEq + Eq + Hash, const N: usize> Iterator for IndexedVecXIter<'a, T, N> {
type Item = &'a VecX<T, N>;
fn next(&mut self) -> Option<Self::Item> {
if self.current_index < self.collection.indices.len() {
self.current_index += 1;
Some(&self.collection[self.current_index])
} else {
None
}
}
}