Skip to content

Commit 432aa95

Browse files
Merge pull request #75 from frankmcsherry/homogenous_enums
Enum containers avoid per-element metadata for homogenous collections
2 parents b3297fb + 8fa8475 commit 432aa95

File tree

3 files changed

+342
-54
lines changed

3 files changed

+342
-54
lines changed

columnar_derive/src/lib.rs

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -604,15 +604,13 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
604604
/// Derived columnar container for an enum.
605605
#derive
606606
#[allow(non_snake_case)]
607-
#vis struct #c_ident < #(#container_types,)* CVar = Vec<u8>, COff = Vec<u64>, >{
607+
#vis struct #c_ident < #(#container_types,)* CVar = Vec<u8>, COff = Vec<u64>, CC = u64, >{
608608
#(
609609
/// Container for #names.
610610
pub #names : #container_types,
611611
)*
612-
/// Container for variant.
613-
pub variant: CVar,
614-
/// Container for offset.
615-
pub offset: COff,
612+
/// Discriminant tracking for variants.
613+
pub indexes: ::columnar::Discriminant<CVar, COff, CC>,
616614
}
617615
}
618616
};
@@ -656,9 +654,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
656654
syn::Fields::Unit => {
657655
quote! {
658656
#name::#variant => {
659-
self.offset.push(self.#variant.len() as u64);
657+
self.indexes.push(#index as u8, self.#variant.len() as u64);
660658
self.#variant.push(());
661-
self.variant.push(#index as u8);
662659
}
663660
}
664661
}
@@ -670,9 +667,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
670667

671668
quote! {
672669
#name::#variant( #(#temp_names),* ) => {
673-
self.offset.push(self.#variant.len() as u64);
670+
self.indexes.push(#index as u8, self.#variant.len() as u64);
674671
self.#variant.push((#(#temp_names),*));
675-
self.variant.push(#index as u8);
676672
},
677673
}
678674
}
@@ -711,9 +707,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
711707
syn::Fields::Unit => {
712708
quote! {
713709
#name::#variant => {
714-
self.offset.push(self.#variant.len() as u64);
710+
self.indexes.push(#index as u8, self.#variant.len() as u64);
715711
self.#variant.push(());
716-
self.variant.push(#index as u8);
717712
}
718713
}
719714
}
@@ -725,9 +720,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
725720

726721
quote! {
727722
#name::#variant( #(#temp_names),* ) => {
728-
self.offset.push(self.#variant.len() as u64);
723+
self.indexes.push(#index as u8, self.#variant.len() as u64);
729724
self.#variant.push((#(#temp_names),*));
730-
self.variant.push(#index as u8);
731725
},
732726
}
733727
}
@@ -778,9 +772,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
778772
match item {
779773
#(
780774
#r_ident::#names(x) => {
781-
self.offset.push(self.#names.len() as u64);
775+
self.indexes.push(#numbers as u8, self.#names.len() as u64);
782776
self.#names.push(x);
783-
self.variant.push(#numbers as u8);
784777
},
785778
)*
786779
}
@@ -790,9 +783,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
790783
};
791784

792785
let index_own = {
793-
let impl_gen = quote! { < #(#container_types,)* CVal, COff> };
794-
let ty_gen = quote! { < #(#container_types,)* CVal, COff> };
795-
let where_clause = quote! { where #(#container_types: ::columnar::Index,)* CVal: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64> };
786+
let impl_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
787+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
788+
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> };
796789

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

@@ -804,8 +797,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
804797
type Ref = #index_type;
805798
#[inline(always)]
806799
fn get(&self, index: usize) -> Self::Ref {
807-
match self.variant.index_as(index) as usize {
808-
#( #numbers => #r_ident::#names(self.#names.get(self.offset.index_as(index) as usize)), )*
800+
let (variant, offset) = self.indexes.get(index);
801+
match variant as usize {
802+
#( #numbers => #r_ident::#names(self.#names.get(offset as usize)), )*
809803
x => panic!("Unacceptable discriminant found: {:?}", x),
810804
}
811805
}
@@ -814,9 +808,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
814808
};
815809

816810
let index_ref = {
817-
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVal, COff> };
818-
let ty_gen = quote! { < #(#container_types,)* CVal, COff> };
819-
let where_clause = quote! { where #(&'columnar #container_types: ::columnar::Index,)* CVal: ::columnar::Len + ::columnar::IndexAs<u8>, COff: ::columnar::Len + ::columnar::IndexAs<u64> };
811+
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff, CC> };
812+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
813+
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> };
820814

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

@@ -828,8 +822,9 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
828822
type Ref = #index_type;
829823
#[inline(always)]
830824
fn get(&self, index: usize) -> Self::Ref {
831-
match self.variant.index_as(index) as usize {
832-
#( #numbers => #r_ident::#names((&self.#names).get(self.offset.index_as(index) as usize)), )*
825+
let (variant, offset) = self.indexes.get(index);
826+
match variant as usize {
827+
#( #numbers => #r_ident::#names((&self.#names).get(offset as usize)), )*
833828
x => panic!("Unacceptable discriminant found: {:?}", x),
834829
}
835830
}
@@ -848,42 +843,40 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
848843
#[inline(always)]
849844
fn clear(&mut self) {
850845
#(self.#names.clear();)*
851-
self.variant.clear();
852-
self.offset.clear();
846+
self.indexes.clear();
853847
}
854848
}
855849
}
856850
};
857851

858852
let length = {
859853

860-
let impl_gen = quote! { < #(#container_types,)* CVar, COff> };
861-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
854+
let impl_gen = quote! { < #(#container_types,)* CVar, COff, CC> };
855+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
862856

863857
quote! {
864-
impl #impl_gen ::columnar::Len for #c_ident #ty_gen where CVar: ::columnar::Len {
858+
impl #impl_gen ::columnar::Len for #c_ident #ty_gen where CVar: ::columnar::Len, CC: ::columnar::common::index::CopyAs<u64> {
865859
#[inline(always)]
866860
fn len(&self) -> usize {
867-
self.variant.len()
861+
self.indexes.len()
868862
}
869863
}
870864
}
871865
};
872866

873867
let as_bytes = {
874868

875-
let impl_gen = quote! { < 'a, #(#container_types,)* CVar, COff> };
876-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
877-
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>,)* CVar: ::columnar::AsBytes<'a>, COff: ::columnar::AsBytes<'a> };
869+
let impl_gen = quote! { < 'a, #(#container_types,)* CVar, COff, CC> };
870+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
871+
let where_clause = quote! { where #(#container_types: ::columnar::AsBytes<'a>,)* ::columnar::Discriminant<CVar, COff, CC>: ::columnar::AsBytes<'a> };
878872

879873
quote! {
880874
impl #impl_gen ::columnar::AsBytes<'a> for #c_ident #ty_gen #where_clause {
881875
#[inline(always)]
882876
fn as_bytes(&self) -> impl Iterator<Item=(u64, &'a [u8])> {
883877
let iter = None.into_iter();
884878
#( let iter = ::columnar::chain(iter,self.#names.as_bytes()); )*
885-
let iter = ::columnar::chain(iter, self.variant.as_bytes());
886-
let iter = ::columnar::chain(iter, self.offset.as_bytes());
879+
let iter = ::columnar::chain(iter, self.indexes.as_bytes());
887880
iter
888881
}
889882
}
@@ -892,20 +885,19 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
892885

893886
let from_bytes = {
894887

895-
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff> };
896-
let ty_gen = quote! { < #(#container_types,)* CVar, COff > };
897-
let where_clause = quote! { where #(#container_types: ::columnar::FromBytes<'columnar>,)* CVar: ::columnar::FromBytes<'columnar>, COff: ::columnar::FromBytes<'columnar> };
888+
let impl_gen = quote! { < 'columnar, #(#container_types,)* CVar, COff, CC> };
889+
let ty_gen = quote! { < #(#container_types,)* CVar, COff, CC > };
890+
let where_clause = quote! { where #(#container_types: ::columnar::FromBytes<'columnar>,)* ::columnar::Discriminant<CVar, COff, CC>: ::columnar::FromBytes<'columnar> };
898891

899892
quote! {
900893
#[allow(non_snake_case)]
901894
impl #impl_gen ::columnar::FromBytes<'columnar> for #c_ident #ty_gen #where_clause {
902-
const SLICE_COUNT: usize = 0 #(+ <#container_types>::SLICE_COUNT)* + CVar::SLICE_COUNT + COff::SLICE_COUNT;
895+
const SLICE_COUNT: usize = 0 #(+ <#container_types>::SLICE_COUNT)* + <::columnar::Discriminant<CVar, COff, CC>>::SLICE_COUNT;
903896
#[inline(always)]
904897
fn from_bytes(bytes: &mut impl Iterator<Item=&'columnar [u8]>) -> Self {
905898
Self {
906899
#(#names: ::columnar::FromBytes::from_bytes(bytes),)*
907-
variant: ::columnar::FromBytes::from_bytes(bytes),
908-
offset: ::columnar::FromBytes::from_bytes(bytes),
900+
indexes: ::columnar::FromBytes::from_bytes(bytes),
909901
}
910902
}
911903
#[inline(always)]
@@ -915,10 +907,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
915907
let #names = <#container_types>::from_byte_slices(&bytes[_offset .. _offset + <#container_types>::SLICE_COUNT]);
916908
_offset += <#container_types>::SLICE_COUNT;
917909
)*
918-
let variant = CVar::from_byte_slices(&bytes[_offset .. _offset + CVar::SLICE_COUNT]);
919-
_offset += CVar::SLICE_COUNT;
920-
let offset = COff::from_byte_slices(&bytes[_offset ..]);
921-
Self { #(#names,)* variant, offset }
910+
let indexes = <::columnar::Discriminant<CVar, COff, CC>>::from_byte_slices(&bytes[_offset ..]);
911+
Self { #(#names,)* indexes }
922912
}
923913
}
924914
}
@@ -1027,21 +1017,19 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10271017

10281018
impl < #(#container_names : ::columnar::Borrow ),* > ::columnar::Borrow for #c_ident < #(#container_names),* > {
10291019
type Ref<'a> = #r_ident < #( <#container_names as ::columnar::Borrow>::Ref<'a> ,)* > where Self: 'a, #(#container_names: 'a,)*;
1030-
type Borrowed<'a> = #c_ident < #( < #container_names as ::columnar::Borrow >::Borrowed<'a>, )* &'a [u8], &'a [u64] > where #(#container_names: 'a,)*;
1020+
type Borrowed<'a> = #c_ident < #( < #container_names as ::columnar::Borrow >::Borrowed<'a>, )* &'a [u8], &'a [u64], &'a u64 > where #(#container_names: 'a,)*;
10311021
#[inline(always)]
10321022
fn borrow<'a>(&'a self) -> Self::Borrowed<'a> {
10331023
#c_ident {
10341024
#(#names: self.#names.borrow(),)*
1035-
variant: self.variant.borrow(),
1036-
offset: self.offset.borrow(),
1025+
indexes: self.indexes.borrow(),
10371026
}
10381027
}
10391028
#[inline(always)]
10401029
fn reborrow<'b, 'a: 'b>(thing: Self::Borrowed<'a>) -> Self::Borrowed<'b> {
10411030
#c_ident {
10421031
#(#names: <#container_names as ::columnar::Borrow>::reborrow(thing.#names),)*
1043-
variant: <Vec<u8> as ::columnar::Borrow>::reborrow(thing.variant),
1044-
offset: <Vec<u64> as ::columnar::Borrow>::reborrow(thing.offset),
1032+
indexes: <::columnar::Discriminant as ::columnar::Borrow>::reborrow(thing.indexes),
10451033
}
10461034
}
10471035
#[inline(always)]
@@ -1057,13 +1045,36 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10571045

10581046
fn reserve_for<'a, I>(&mut self, selves: I) where Self: 'a, I: Iterator<Item = Self::Borrowed<'a>> + Clone {
10591047
#( self.#names.reserve_for(selves.clone().map(|x| x.#names)); )*
1060-
self.variant.reserve_for(selves.clone().map(|x| x.variant));
1061-
self.offset.reserve_for(selves.map(|x| x.offset));
1048+
self.indexes.reserve_for(selves.map(|x| x.indexes));
10621049
}
10631050
}
10641051
}
10651052
};
10661053

1054+
let try_unwrap = {
1055+
let impl_gen = quote! { < #(#container_types),* > };
1056+
let ty_gen = quote! { < #(#container_types),* > };
1057+
1058+
let numbers = (0u8 ..);
1059+
let methods = names.iter().zip(container_types.iter()).zip(numbers).map(|((name, ctype), index)| {
1060+
let try_name = syn::Ident::new(&format!("try_unwrap_{}", name), name.span());
1061+
quote! {
1062+
/// Returns the #name container if all elements are #name.
1063+
#[inline]
1064+
pub fn #try_name(&self) -> Option<&#ctype> {
1065+
if self.indexes.homogeneous() == Some(#index) { Some(&self.#name) } else { None }
1066+
}
1067+
}
1068+
});
1069+
1070+
quote! {
1071+
#[allow(non_snake_case)]
1072+
impl #impl_gen #c_ident #ty_gen {
1073+
#( #methods )*
1074+
}
1075+
}
1076+
};
1077+
10671078
quote! {
10681079

10691080
#container_struct
@@ -1083,6 +1094,8 @@ fn derive_enum(name: &syn::Ident, generics: &syn:: Generics, data_enum: syn::Dat
10831094

10841095
#columnar_impl
10851096

1097+
#try_unwrap
1098+
10861099
}.into()
10871100
}
10881101

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)