Skip to content

Commit b8b62a6

Browse files
committed
Enum containers avoid per-element metadata for homogenous collections
1 parent e29e702 commit b8b62a6

File tree

3 files changed

+328
-49
lines changed

3 files changed

+328
-49
lines changed

columnar_derive/src/lib.rs

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -589,15 +589,13 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
589589
/// Derived columnar container for an enum.
590590
#derive
591591
#[allow(non_snake_case)]
592-
#vis struct #c_ident < #(#container_types,)* CVar = Vec<u8>, COff = Vec<u64>, >{
592+
#vis struct #c_ident < #(#container_types,)* CVar = Vec<u8>, COff = Vec<u64>, CC = u64, >{
593593
#(
594594
/// Container for #names.
595595
pub #names : #container_types,
596596
)*
597-
/// Container for variant.
598-
pub variant: CVar,
599-
/// Container for offset.
600-
pub offset: COff,
597+
/// Discriminant tracking for variants.
598+
pub indexes: ::columnar::Discriminant<CVar, COff, CC>,
601599
}
602600
}
603601
};
@@ -641,9 +639,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
641639
syn::Fields::Unit => {
642640
quote! {
643641
#name::#variant => {
644-
self.offset.push(self.#variant.len() as u64);
642+
self.indexes.push(#index as u8, self.#variant.len() as u64);
645643
self.#variant.push(());
646-
self.variant.push(#index as u8);
647644
}
648645
}
649646
}
@@ -655,9 +652,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
655652

656653
quote! {
657654
#name::#variant( #(#temp_names),* ) => {
658-
self.offset.push(self.#variant.len() as u64);
655+
self.indexes.push(#index as u8, self.#variant.len() as u64);
659656
self.#variant.push((#(#temp_names),*));
660-
self.variant.push(#index as u8);
661657
},
662658
}
663659
}
@@ -696,9 +692,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
696692
syn::Fields::Unit => {
697693
quote! {
698694
#name::#variant => {
699-
self.offset.push(self.#variant.len() as u64);
695+
self.indexes.push(#index as u8, self.#variant.len() as u64);
700696
self.#variant.push(());
701-
self.variant.push(#index as u8);
702697
}
703698
}
704699
}
@@ -710,9 +705,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
710705

711706
quote! {
712707
#name::#variant( #(#temp_names),* ) => {
713-
self.offset.push(self.#variant.len() as u64);
708+
self.indexes.push(#index as u8, self.#variant.len() as u64);
714709
self.#variant.push((#(#temp_names),*));
715-
self.variant.push(#index as u8);
716710
},
717711
}
718712
}
@@ -763,9 +757,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
763757
match item {
764758
#(
765759
#r_ident::#names(x) => {
766-
self.offset.push(self.#names.len() as u64);
760+
self.indexes.push(#numbers as u8, self.#names.len() as u64);
767761
self.#names.push(x);
768-
self.variant.push(#numbers as u8);
769762
},
770763
)*
771764
}
@@ -775,9 +768,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
775768
};
776769

777770
let index_own = {
778-
let impl_gen = quote! { < #(#container_types,)* CVal, COff> };
779-
let ty_gen = quote! { < #(#container_types,)* CVal, COff> };
780-
let where_clause = quote! { where #(#container_types: ::columnar::Index,)* CVal: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64> };
771+
let impl_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
772+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
773+
let where_clause = quote! { where #(#container_types: ::columnar::Index,)* CVar: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64>, CC: ::columnar::common::index::CopyAs<u64> };
781774

782775
let index_type = quote! { #r_ident < #(<#container_types as ::columnar::Index>::Ref,)* > };
783776

@@ -789,8 +782,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
789782
type Ref = #index_type;
790783
#[inline(always)]
791784
fn get(&self, index: usize) -> Self::Ref {
792-
match self.variant.index_as(index) as usize {
793-
#( #numbers => #r_ident::#names(self.#names.get(self.offset.index_as(index) as usize)), )*
785+
let (variant, offset) = self.indexes.get(index);
786+
match variant as usize {
787+
#( #numbers => #r_ident::#names(self.#names.get(offset as usize)), )*
794788
x => panic!("Unacceptable discriminant found: {:?}", x),
795789
}
796790
}
@@ -799,9 +793,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
799793
};
800794

801795
let index_ref = {
802-
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVal, COff> };
803-
let ty_gen = quote! { < #(#container_types,)* CVal, COff> };
804-
let where_clause = quote! { where #(&'columnar #container_types: ::columnar::Index,)* CVal: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64> };
796+
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff, CC> };
797+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
798+
let where_clause = quote! { where #(&'columnar #container_types: ::columnar::Index,)* CVar: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64>, CC: ::columnar::common::index::CopyAs<u64> };
805799

806800
let index_type = quote! { #r_ident < #(<&'columnar #container_types as ::columnar::Index>::Ref,)* > };
807801

@@ -813,8 +807,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
813807
type Ref = #index_type;
814808
#[inline(always)]
815809
fn get(&self, index: usize) -> Self::Ref {
816-
match self.variant.index_as(index) as usize {
817-
#( #numbers => #r_ident::#names((&self.#names).get(self.offset.index_as(index) as usize)), )*
810+
let (variant, offset) = self.indexes.get(index);
811+
match variant as usize {
812+
#( #numbers => #r_ident::#names((&self.#names).get(offset as usize)), )*
818813
x => panic!("Unacceptable discriminant found: {:?}", x),
819814
}
820815
}
@@ -833,42 +828,40 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
833828
#[inline(always)]
834829
fn clear(&mut self) {
835830
#(self.#names.clear();)*
836-
self.variant.clear();
837-
self.offset.clear();
831+
self.indexes.clear();
838832
}
839833
}
840834
}
841835
};
842836

843837
let length = {
844838

845-
let impl_gen = quote! { < #(#container_types,)* CVar, COff> };
846-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
839+
let impl_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
840+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
847841

848842
quote! {
849-
impl #impl_gen ::columnar::Len for #c_ident #ty_gen where CVar: ::columnar::Len {
843+
impl #impl_gen ::columnar::Len for #c_ident #ty_gen where CVar: ::columnar::Len, CC: ::columnar::common::index::CopyAs<u64> {
850844
#[inline(always)]
851845
fn len(&self) -> usize {
852-
self.variant.len()
846+
self.indexes.len()
853847
}
854848
}
855849
}
856850
};
857851

858852
let as_bytes = {
859853

860-
let impl_gen = quote! { < 'a, #(#container_types,)* CVar, COff> };
861-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
862-
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>,)* CVar: ::columnar::AsBytes<'a>, COff: ::columnar::AsBytes<'a> };
854+
let impl_gen = quote! { < 'a, #(#container_types,)* CVar, COff, CC> };
855+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
856+
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>,)* ::columnar::Discriminant<CVar, COff, CC>: ::columnar::AsBytes<'a> };
863857

864858
quote! {
865859
impl #impl_gen ::columnar::AsBytes<'a> for #c_ident #ty_gen #where_clause {
866860
#[inline(always)]
867861
fn as_bytes(&self) -> impl Iterator<Item=(u64, &'a [u8])> {
868862
let iter = None.into_iter();
869863
#( let iter = ::columnar::chain(iter,self.#names.as_bytes()); )*
870-
let iter = ::columnar::chain(iter, self.variant.as_bytes());
871-
let iter = ::columnar::chain(iter, self.offset.as_bytes());
864+
let iter = ::columnar::chain(iter, self.indexes.as_bytes());
872865
iter
873866
}
874867
}
@@ -877,9 +870,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
877870

878871
let from_bytes = {
879872

880-
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff> };
881-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
882-
let where_clause = quote! { where #(#container_types: ::columnar::FromBytes<'columnar>,)* CVar: ::columnar::FromBytes<'columnar>, COff: ::columnar::FromBytes<'columnar> };
873+
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff, CC> };
874+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
875+
let where_clause = quote! { where #(#container_types: ::columnar::FromBytes<'columnar>,)* ::columnar::Discriminant<CVar, COff, CC>: ::columnar::FromBytes<'columnar> };
883876

884877
quote! {
885878
#[allow(non_snake_case)]
@@ -888,8 +881,7 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
888881
fn from_bytes(bytes: &mut impl Iterator<Item=&'columnar [u8]>) -> Self {
889882
Self {
890883
#(#names: ::columnar::FromBytes::from_bytes(bytes),)*
891-
variant: ::columnar::FromBytes::from_bytes(bytes),
892-
offset: ::columnar::FromBytes::from_bytes(bytes),
884+
indexes: ::columnar::FromBytes::from_bytes(bytes),
893885
}
894886
}
895887
}
@@ -999,21 +991,19 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
999991

1000992
impl < #(#container_names : ::columnar::Borrow ),* > ::columnar::Borrow for #c_ident < #(#container_names),* > {
1001993
type Ref<'a> = #r_ident < #( <#container_names as ::columnar::Borrow>::Ref<'a> ,)* > where Self: 'a, #(#container_names: 'a,)*;
1002-
type Borrowed<'a> = #c_ident < #( < #container_names as ::columnar::Borrow >::Borrowed<'a>, )* &'a [u8], &'a [u64] > where #(#container_names: 'a,)*;
994+
type Borrowed<'a> = #c_ident < #( < #container_names as ::columnar::Borrow >::Borrowed<'a>, )* &'a [u8], &'a [u64], &'a u64 > where #(#container_names: 'a,)*;
1003995
#[inline(always)]
1004996
fn borrow<'a>(&'a self) -> Self::Borrowed<'a> {
1005997
#c_ident {
1006998
#(#names: self.#names.borrow(),)*
1007-
variant: self.variant.borrow(),
1008-
offset: self.offset.borrow(),
999+
indexes: self.indexes.borrow(),
10091000
}
10101001
}
10111002
#[inline(always)]
10121003
fn reborrow<'b, 'a: 'b>(thing: Self::Borrowed<'a>) -> Self::Borrowed<'b> {
10131004
#c_ident {
10141005
#(#names: <#container_names as ::columnar::Borrow>::reborrow(thing.#names),)*
1015-
variant: <Vec<u8> as ::columnar::Borrow>::reborrow(thing.variant),
1016-
offset: <Vec<u64> as ::columnar::Borrow>::reborrow(thing.offset),
1006+
indexes: <::columnar::Discriminant as ::columnar::Borrow>::reborrow(thing.indexes),
10171007
}
10181008
}
10191009
#[inline(always)]
@@ -1029,13 +1019,36 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10291019

10301020
fn reserve_for<'a, I>(&mut self, selves: I) where Self: 'a, I: Iterator<Item = Self::Borrowed<'a>> + Clone {
10311021
#( self.#names.reserve_for(selves.clone().map(|x| x.#names)); )*
1032-
self.variant.reserve_for(selves.clone().map(|x| x.variant));
1033-
self.offset.reserve_for(selves.map(|x| x.offset));
1022+
self.indexes.reserve_for(selves.map(|x| x.indexes));
10341023
}
10351024
}
10361025
}
10371026
};
10381027

1028+
let try_unwrap = {
1029+
let impl_gen = quote! { < #(#container_types),* > };
1030+
let ty_gen = quote! { < #(#container_types),* > };
1031+
1032+
let numbers = (0u8 ..);
1033+
let methods = names.iter().zip(container_types.iter()).zip(numbers).map(|((name, ctype), index)| {
1034+
let try_name = syn::Ident::new(&format!("try_unwrap_{}", name), name.span());
1035+
quote! {
1036+
/// Returns the #name container if all elements are #name.
1037+
#[inline]
1038+
pub fn #try_name(&self) -> Option<&#ctype> {
1039+
if self.indexes.homogeneous() == Some(#index) { Some(&self.#name) } else { None }
1040+
}
1041+
}
1042+
});
1043+
1044+
quote! {
1045+
#[allow(non_snake_case)]
1046+
impl #impl_gen #c_ident #ty_gen {
1047+
#( #methods )*
1048+
}
1049+
}
1050+
};
1051+
10391052
quote! {
10401053

10411054
#container_struct
@@ -1055,6 +1068,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10551068

10561069
#columnar_impl
10571070

1071+
#try_unwrap
1072+
10581073
}.into()
10591074
}
10601075

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub use bytemuck;
2626

2727
pub use vector::Vecs;
2828
pub use string::Strings;
29-
pub use sums::{rank_select::RankSelect, result::Results, option::Options};
29+
pub use sums::{rank_select::RankSelect, result::Results, option::Options, discriminant::Discriminant};
3030
pub use lookback::{Repeats, Lookbacks};
3131

3232
/// A type that can be represented in columnar form.

0 commit comments

Comments
 (0)