Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support bitfield allocation units larger than 64 bits #1158

Merged
merged 1 commit into from
Nov 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bindgen-integration/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl ParseCallbacks for MacroCallback {
}

fn main() {
gcc::Config::new()
gcc::Build::new()
.cpp(true)
.file("cpp/Test.cc")
.compile("libtest.a");
Expand Down
45 changes: 31 additions & 14 deletions bindgen-integration/cpp/Test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ Date2::assert(unsigned short nWeekDay,
unsigned short nYear,
unsigned short byte)
{
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->nYear == nYear &&
this->byte == byte;
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->nYear == nYear &&
this->byte == byte;
}

bool
Expand All @@ -83,22 +83,39 @@ Fifth::assert(unsigned short nWeekDay,
unsigned short nYear,
unsigned char byte)
{
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->nYear == nYear &&
this->byte == byte;
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->nYear == nYear &&
this->byte == byte;
}

bool
Sixth::assert(unsigned char byte,
unsigned char nWeekDay,
unsigned char nMonth,
unsigned char nMonthDay) {
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->byte == byte;
return this->nWeekDay == nWeekDay &&
this->nMonthDay == nMonthDay &&
this->nMonth == nMonth &&
this->byte == byte;
};

bool
Seventh::assert(bool first,
int second,
unsigned short third,
unsigned int fourth,
unsigned short fifth,
bool sixth,
int seventh) {
return this->first_one_bit == first &&
this->second_thirty_bits == second &&
this->third_two_bits == third &&
this->fourth_thirty_bits == fourth &&
this->fifth_two_bits == fifth &&
this->sixth_one_bit == sixth &&
this->seventh_thirty_bits == seventh;
};

} // namespace bitfields
18 changes: 18 additions & 0 deletions bindgen-integration/cpp/Test.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,24 @@ struct Sixth {
unsigned char nMonthDay);
};

struct Seventh {
bool first_one_bit : 1;
unsigned int second_thirty_bits : 30;
unsigned short third_two_bits : 2;
unsigned int fourth_thirty_bits : 30;
unsigned short fifth_two_bits : 2;
bool sixth_one_bit : 1;
unsigned int seventh_thirty_bits : 30;

/// Returns true if the bitfields match the arguments, false otherwise.
bool assert(bool first,
int second,
unsigned short third,
unsigned int fourth,
unsigned short fifth,
bool sixth,
int seventh);
};

} // namespace bitfields

Expand Down
33 changes: 32 additions & 1 deletion bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,42 @@ fn test_bitfields_sixth() {
});
}

#[test]
fn test_bitfields_seventh() {
let mut large: bindings::bitfields::Seventh = unsafe {
mem::zeroed()
};

assert!(unsafe {
large.assert(false, 0, 0, 0, 0, false, 0)
});

large.set_first_one_bit(true);
large.set_second_thirty_bits(375028802);
large.set_third_two_bits(2);
large.set_fourth_thirty_bits(643472885);
large.set_fifth_two_bits(3);
large.set_sixth_one_bit(true);
large.set_seventh_thirty_bits(1061657575);

assert!(unsafe {
large.assert(true, 375028802, 2, 643472885, 3, true, 1061657575)
});

assert_eq!(large.first_one_bit(), true);
assert_eq!(large.second_thirty_bits(), 375028802);
assert_eq!(large.third_two_bits(), 2);
assert_eq!(large.fourth_thirty_bits(), 643472885);
assert_eq!(large.fifth_two_bits(), 3);
assert_eq!(large.sixth_one_bit(), true);
assert_eq!(large.seventh_thirty_bits(), 1061657575);
}

#[test]
fn test_bitfield_constructors() {
use std::mem;
let mut first = bindings::bitfields::First {
_bitfield_1: unsafe { mem::transmute(bindings::bitfields::First::new_bitfield_1(1, 2, 3)) }
_bitfield_1: bindings::bitfields::First::new_bitfield_1(1, 2, 3)
};
assert!(unsafe {
first.assert(1, 2, 3)
Expand Down
82 changes: 82 additions & 0 deletions src/codegen/bitfield_unit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
storage: Storage,
align: [Align; 0],
}

impl<Storage, Align> __BindgenBitfieldUnit<Storage, Align>
where
Storage: AsRef<[u8]> + AsMut<[u8]>,
{
#[inline]
pub fn new(storage: Storage) -> Self {
Self {
storage,
align: [],
}
}

#[inline]
pub fn get_bit(&self, index: usize) -> bool {
debug_assert!(index / 8 < self.storage.as_ref().len());

let byte_index = index / 8;
let byte = self.storage.as_ref()[byte_index];

let bit_index = index % 8;
let mask = 1 << bit_index;

byte & mask == mask
}

#[inline]
pub fn set_bit(&mut self, index: usize, val: bool) {
debug_assert!(index / 8 < self.storage.as_ref().len());

let byte_index = index / 8;
let byte = &mut self.storage.as_mut()[byte_index];

let bit_index = index % 8;
let mask = 1 << bit_index;

if val {
*byte |= mask;
} else {
*byte &= !mask;
}
}

#[inline]
pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());

let mut val = 0;

for i in 0..(bit_width as usize) {
if self.get_bit(i + bit_offset) {
val |= 1 << i;
}
}

val
}

#[inline]
pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) {
debug_assert!(bit_width <= 64);
debug_assert!(bit_offset / 8 < self.storage.as_ref().len());
debug_assert!((bit_offset + (bit_width as usize)) / 8 <= self.storage.as_ref().len());

for i in 0..(bit_width as usize) {
let mask = 1 << i;
let val_bit_is_set = val & mask == mask;
self.set_bit(i + bit_offset, val_bit_is_set);
}
}
}
Loading