Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C++ (Circle)
CIRCT
Clean
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Nim
Objective-C
Objective-C++
OCaml
OpenCL C
Pascal
Pony
Python
Racket
Ruby
Rust
Snowball
Scala
Solidity
Spice
Swift
LLVM TableGen
Toit
TypeScript Native
V
Vala
Visual Basic
WASM
Zig
Javascript
GIMPLE
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.9.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC)
Options
Source code
#![feature(specialization)] use std::{cmp, fmt::Debug}; static BIT_MASK: [u8; 8] = [1, 2, 4, 8, 16, 32, 64, 128]; #[inline] pub unsafe fn get_bit_raw(ptr: *const u8, i: usize) -> bool { (*ptr.add(i >> 3) & BIT_MASK[i & 7]) != 0 } // Type your code here, or load an example. #[derive(Debug, PartialEq)] pub enum Type { Boolean, Byte, Short, Integer, Long, Float, Double, Decimal(u8, i8), String, Binary, Timestamp, Date, } /// Unlike `Type`, `TypeKind` doesn't carry extra information about the type itself, such as /// decimal precision & scale. Instead, it is merely a token that is used to do runtime case /// analysis depending on the actual type. It can be obtained from a `TypeTrait` generic parameter. #[derive(Debug, PartialEq)] pub enum TypeKind { Boolean, Byte, Short, Integer, Long, Float, Double, Decimal, String, Binary, Timestamp, Date, } impl TypeKind { /// Returns the size of this type, in bytes. pub fn value_size(&self) -> usize { match self { // value size is not meaningful for boolean, so dummy value 0 here TypeKind::Boolean => 0, TypeKind::Byte => 1, TypeKind::Short => 2, TypeKind::Integer | TypeKind::Float => 4, TypeKind::Long | TypeKind::Double => 8, TypeKind::Decimal => 16, TypeKind::String | TypeKind::Binary => 16, TypeKind::Timestamp => 8, TypeKind::Date => 4, } } } pub const STRING_VIEW_PREFIX_LEN: usize = 4; #[repr(C, align(16))] #[derive(Clone, Copy, Debug)] pub struct StringView { pub len: u32, pub prefix: [u8; STRING_VIEW_PREFIX_LEN], pub ptr: usize, } impl StringView { pub fn as_utf8_str(&self) -> &str { unsafe { let slice = std::slice::from_raw_parts(self.ptr as *const u8, self.len as usize); std::str::from_utf8_unchecked(slice) } } } impl PartialEq for StringView { fn eq(&self, other: &Self) -> bool { if self.len != other.len { return false; } if self.prefix != other.prefix { return false; } self.as_utf8_str() == other.as_utf8_str() } } pub trait NativeEqual { fn is_equal(&self, other: &Self) -> bool; } macro_rules! make_native_equal { ($native_ty:ty) => { impl NativeEqual for $native_ty { fn is_equal(&self, other: &Self) -> bool { self == other } } }; } make_native_equal!(bool); make_native_equal!(i8); make_native_equal!(i16); make_native_equal!(i32); make_native_equal!(i64); make_native_equal!(i128); make_native_equal!(StringView); impl NativeEqual for f32 { fn is_equal(&self, other: &Self) -> bool { self.total_cmp(other) == cmp::Ordering::Equal } } impl NativeEqual for f64 { fn is_equal(&self, other: &Self) -> bool { self.total_cmp(other) == cmp::Ordering::Equal } } pub trait NativeType: Debug + NativeEqual {} impl NativeType for bool {} impl NativeType for i8 {} impl NativeType for i16 {} impl NativeType for i32 {} impl NativeType for i64 {} impl NativeType for i128 {} impl NativeType for f32 {} impl NativeType for f64 {} impl NativeType for StringView {} /// A trait for Boson data type. This should only be used as generic parameter during method /// invocations. pub trait TypeTrait: 'static { type Native: NativeType + Copy; fn type_kind() -> TypeKind; } macro_rules! make_type_trait { ($name:ident, $native_ty:ty, $kind:path) => { pub struct $name {} impl TypeTrait for $name { type Native = $native_ty; fn type_kind() -> TypeKind { $kind } } }; } make_type_trait!(BoolType, bool, TypeKind::Boolean); make_type_trait!(ByteType, i8, TypeKind::Byte); make_type_trait!(ShortType, i16, TypeKind::Short); make_type_trait!(IntegerType, i32, TypeKind::Integer); make_type_trait!(LongType, i64, TypeKind::Long); make_type_trait!(FloatType, f32, TypeKind::Float); make_type_trait!(DoubleType, f64, TypeKind::Double); make_type_trait!(DecimalType, i128, TypeKind::Decimal); make_type_trait!(StringType, StringView, TypeKind::String); make_type_trait!(BinaryType, StringView, TypeKind::Binary); make_type_trait!(TimestampType, i64, TypeKind::Timestamp); make_type_trait!(DateType, i32, TypeKind::Date); pub struct Buffer(*const u8); impl Buffer { pub fn as_ptr(&self) -> *const u8 { self.0 } } struct ValueBuffer { ptr: *const u8, /// Keep the `ptr` alive original_buffers: Vec<Buffer>, } impl ValueBuffer { /// Returns the raw pointer for the data in this value buffer. /// NOTE: caller of this should NOT store the raw pointer to avoid dangling pointers. pub fn as_ptr(&self) -> *const u8 { self.ptr } pub fn new(buffer: Buffer) -> Self { Self { ptr: buffer.0, original_buffers: vec![buffer], } } } struct IndexBuffer { ptr: *const u8, /// Keep the `ptr` alive. buf: Option<Buffer>, } impl IndexBuffer { pub fn new(buf: Buffer) -> Self { let ptr = buf.as_ptr(); Self { buf: Some(buf), ptr, } } pub fn empty() -> Self { Self { buf: None, ptr: std::ptr::null(), } } #[inline] pub fn get(&self, i: usize) -> usize { unsafe { *(self.ptr.add(i << 2) as *const i32) as usize } } } /// A vector that holds elements of plan types (i.e., no nested type such as list, map, struct). pub struct PlainVector { /// The data type for elements in this vector data_type: Type, /// Total number of values in this vector num_values: usize, /// Total number of nulls in this vector. Must <= `num_values`. num_nulls: usize, /// The value buffer value_buffer: ValueBuffer, /// Number of bytes for each element in the vector value_size: usize, /// Offsets into buffers offset: usize, /// The validity buffer. If empty, all values in this vector are not null. validity_buffer: Option<Buffer>, /// Whether this vector is dictionary encoded is_dictionary: bool, /// Indices (or dictionary keys) when `is_dictionary` is true. Otherwise, this is always /// an empty vector. indices: IndexBuffer, } impl PlainVector { pub fn new(data_type: Type, num_values: usize, values: Buffer) -> Self { Self { data_type, num_values, num_nulls: 0, value_buffer: ValueBuffer::new(values), value_size: 4, offset: 0, validity_buffer: None, is_dictionary: false, indices: IndexBuffer::empty(), } } } trait ValueGetter<T: TypeTrait> { fn value(&self, idx: usize) -> T::Native; } impl<T: TypeTrait> ValueGetter<T> for PlainVector { default fn value(&self, idx: usize) -> T::Native { let offset = self.offset(idx); unsafe { let offset = offset * self.value_size; *(self.value_buffer.as_ptr().add(offset) as *const T::Native) } } } impl ValueGetter<BoolType> for PlainVector { fn value(&self, idx: usize) -> bool { let offset = self.offset(idx); unsafe { get_bit_raw(self.value_buffer.as_ptr(), offset) } } } impl PlainVector { /// Returns the data type of this vector. pub fn data_type(&self) -> &Type { &self.data_type } /// Returns the total number of elements in this vector. pub fn len(&self) -> usize { self.num_values } /// Returns the total number of nulls in this vector. pub fn num_nulls(&self) -> usize { self.num_nulls } /// Whether there is any null in this vector. pub fn has_null(&self) -> bool { self.num_nulls > 0 } /// Whether the element at `idx` is null. pub fn is_null(&self, idx: usize) -> bool { if let Some(validity_buffer) = &self.validity_buffer { unsafe { return !get_bit_raw(validity_buffer.as_ptr(), self.offset + idx); } } false } #[inline(always)] pub fn value<T: TypeTrait>(&self, idx: usize) -> T::Native { <dyn ValueGetter<T>>::value(self, idx) } #[inline(always)] fn offset(&self, idx: usize) -> usize { let idx = self.offset + idx; if self.is_dictionary { self.indices.get(idx) } else { idx } } } pub fn main() { let mut v = vec![0; 1024]; v[100] = 10; v[200] = 20; let ptr = v.as_slice().as_ptr(); let vector = PlainVector::new(Type::Integer, 9999, Buffer(ptr)); let mut total = 0; for i in 0..v.len() { if !vector.is_null(i) { let k = vector.value::<IntegerType>(i) + 99; total += k; } } println!("total = {}", total); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
About the author
Statistics
Changelog
Version tree