Skip to content

Instantly share code, notes, and snippets.

@kgtkr
Created April 1, 2021 13:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kgtkr/4b2d53fa928b6d7fb4ed377d422af4ac to your computer and use it in GitHub Desktop.
Save kgtkr/4b2d53fa928b6d7fb4ed377d422af4ac to your computer and use it in GitHub Desktop.
branch vs dynamic dispatch vs static
#![feature(test)]
extern crate test;
use std::hint::black_box;
unsafe fn write_pixel_rgb(buf: &mut [u8], x: usize, c: [u8; 3]) {
*buf.get_unchecked_mut(4 * x + 0) = c[0];
*buf.get_unchecked_mut(4 * x + 1) = c[1];
*buf.get_unchecked_mut(4 * x + 2) = c[2];
}
unsafe fn write_pixel_bgr(buf: &mut [u8], x: usize, c: [u8; 3]) {
*buf.get_unchecked_mut(4 * x + 0) = c[2];
*buf.get_unchecked_mut(4 * x + 1) = c[1];
*buf.get_unchecked_mut(4 * x + 2) = c[0];
}
trait Writer {
unsafe fn write_pixel(&self, buf: &mut [u8], x: usize, c: [u8; 3]);
}
struct RGBWriter;
impl Writer for RGBWriter {
unsafe fn write_pixel(&self, buf: &mut [u8], x: usize, c: [u8; 3]) {
write_pixel_rgb(buf, x, c);
}
}
struct BGRWriter;
impl Writer for BGRWriter {
unsafe fn write_pixel(&self, buf: &mut [u8], x: usize, c: [u8; 3]) {
write_pixel_bgr(buf, x, c);
}
}
enum WriterConfig {
RGB,
BGR,
}
struct BranchWriter(WriterConfig);
impl Writer for BranchWriter {
unsafe fn write_pixel(&self, buf: &mut [u8], x: usize, c: [u8; 3]) {
match self.0 {
WriterConfig::RGB => write_pixel_rgb(buf, x, c),
WriterConfig::BGR => write_pixel_bgr(buf, x, c),
}
}
}
impl Writer for &dyn Writer {
unsafe fn write_pixel(&self, buf: &mut [u8], x: usize, c: [u8; 3]) {
(*self).write_pixel(buf, x, c);
}
}
fn test<W: Writer>(writer: W) -> Vec<u8> {
black_box(&writer);
const WIDTH: usize = 1000000;
let mut buf = Vec::with_capacity(4 * WIDTH);
buf.resize(4 * WIDTH, 0);
for i in 0..WIDTH {
unsafe {
black_box(&buf);
writer.write_pixel(&mut buf[..], i, [100, 150, 200]);
}
}
buf
}
fn test_static() -> (Vec<u8>, Vec<u8>) {
(test(RGBWriter), test(BGRWriter))
}
fn test_branch() -> (Vec<u8>, Vec<u8>) {
(
test(BranchWriter(WriterConfig::RGB)),
test(BranchWriter(WriterConfig::BGR)),
)
}
fn test_dynamic_dispatch() -> (Vec<u8>, Vec<u8>) {
(
test(&RGBWriter as &dyn Writer),
test(&BGRWriter as &dyn Writer),
)
}
#[bench]
fn static_bench(b: &mut test::Bencher) {
b.iter(|| test_static())
}
#[bench]
fn branch_bench(b: &mut test::Bencher) {
b.iter(|| test_branch())
}
#[bench]
fn dynamic_dispatch_bench(b: &mut test::Bencher) {
b.iter(|| test_dynamic_dispatch())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment