Git Product home page Git Product logo

bitflags-ts's Introduction

Hi there, I'm John Paul! o/

I'm a full-stack developer and general maker of things. If you want see my work in action, check out my web projects!

bitflags-ts's People

Contributors

github-actions[bot] avatar john-paul-r avatar

Watchers

 avatar

bitflags-ts's Issues

Performance Concerns

Right now, the biggest argument against this package is setup (create enum, create union) performance.

In abstracting away the bitwise operations, we opt-in to JS loops. JS is bad at loops.

In fact, this renders arrays faster for setup, and similar for matching due to the fact that array allocation (['red', 'green', 'blue']) and match checks (arr.includes('red')) are directly translated to C, while BitFlagEnum.union has to execute the comparatively slower JS for loop.

Note: All forms of bitflags (even the abstractions in this package) are faster than arrays for match operations.

Also note: Native bitflag enums are faster for creating unions (Color.Red | Color.Blue) and for matches ((myUnion & Color.Red) === Color.Red). They are slower than arrays for setup, though (one time cost, declaring the TS enum).

Also also note: in the below benchmarks, array match is comparable to the others because 1) that's C code and 2) there are only 3 elements in the array in this test. The bit flag match checks are still O(1), while the array check is O(n).


Because of this, my suggestion remains: use native TS bitflag enums directly.


Benchmark Results

--- Setup/Create 'Enum' ---
  native_bf_setup_3 321.94109540134673
  bitflags_setup_3 1109.872335499525
  bitflags_classes_setup_3 4482.810426294804
  array_setup_3 15.161595900356772
--- Create a size-3 Union ---
  native_bf 11.041500988602637
  bitflags 249.79386930465697
  bitflags_classes_or 2207.856432601809
  bitflags_classes_union 1110.9551441982387
  array 14.696527199447155
--- Match a Single Flag in size-3 Union ---
  native_bf_match_3 10.482809491455555
  bitflags_match_3 12.026449204981327
  bitflags_classes_match_3 12.145723405480386
  array_match_3 19.44586749076843
Benchmark Source
import { bitFlag } from '../src/lib/bitflag';
import { createBitFlagsEnum } from '../src/lib/bitflag_classes';

var groupByName = function (xs: [string, number][]): Record<string, number[]> {
  return xs.reduce((rv, x) => {
    (rv[x[0]] = rv[x[0]] || []).push(x[1]);
    return rv;
  }, {});
};

const testGroup = (
  name: string,
  desiredRuns: number,
  testFns: [string, () => number][]
) => {
  const results: [string, number][] = [];
  for (let i = 0; i < desiredRuns; i++) {
    results.push(
      ...testFns.map<[string, number]>(([name, fn]) => [name, fn()])
    );
  }

  const groupedResults = groupByName(results);

  console.group(`--- ${name} ---`);
  Object.entries(groupedResults).forEach(([name, times]) => {
    const avgTime = times.reduce((sum, cur) => sum + cur / times.length);
    console.log(name, avgTime);
  });

  console.groupEnd();
};

const test = (iterations: number, fn: (i: number) => void): number => {
  let time = 0;
  const start = performance.now();
  for (let i = 0; i < iterations; i++) {
    fn(i);
  }
  time += performance.now() - start;
  return time;
};

const native_bf_setup_3 = () => {
  enum Perms {
    Read = 1 << 1,
    Write = 1 << 2,
    Execute = 1 << 3,
  }
  return Perms;
};

const bitflags_setup_3 = () => {
  return bitFlag('Read', 'Write', 'Execute');
};

const bitflags_classes_setup_3 = () => {
  return createBitFlagsEnum(['Read', 'Write', 'Execute'] as const);
};

const array_setup_3 = () => {
  return ['Read', 'Write', 'Execute'];
};

const iterations = 1000000;
// expected order (fast to slow): array_setup_3, bitflags_setup_3, bitflags_classes_setup_3
testGroup("Setup/Create 'Enum'", 10, [
  ['native_bf_setup_3', () => test(iterations, native_bf_setup_3)],
  ['bitflags_setup_3', () => test(iterations, bitflags_setup_3)],
  [
    'bitflags_classes_setup_3',
    () => test(iterations, bitflags_classes_setup_3),
  ],
  ['array_setup_3', () => test(iterations, array_setup_3)],
]);

{
  // Create Union
  enum native_perms_enum {
    Read = 1 << 1,
    Write = 1 << 2,
    Execute = 1 << 3,
  }
  const native_bf = () => {
    return (
      native_perms_enum.Read |
      native_perms_enum.Write |
      native_perms_enum.Execute
    );
  };

  const bitflags_match_3_enum = bitFlag('Read', 'Write', 'Execute');
  const bitflags = () => {
    return bitflags_match_3_enum.union(
      bitflags_match_3_enum.Read,
      bitflags_match_3_enum.Write,
      bitflags_match_3_enum.Execute
    );
  };

  const bitflags_classes_3_enum = createBitFlagsEnum([
    'Read',
    'Write',
    'Execute',
  ] as const);
  const bitflags_classes_or = () => {
    return bitflags_classes_3_enum.Execute.or(bitflags_classes_3_enum.Read).or(
      bitflags_classes_3_enum.Write
    );
  };

  const bitflags_classes_union = () => {
    return bitflags_classes_3_enum.Execute.union([
      bitflags_classes_3_enum.Read,
      bitflags_classes_3_enum.Write,
    ]);
  };

  const array_3_val = ['Read', 'Write', 'Execute'];
  const array = () => {
    return ['Read', 'Write', 'Execute'];
  };

  testGroup('Create a size-3 Union', 10, [
    ['native_bf', () => test(iterations, native_bf)],
    ['bitflags', () => test(iterations, bitflags)],
    ['bitflags_classes_or', () => test(iterations, bitflags_classes_or)],
    ['bitflags_classes_union', () => test(iterations, bitflags_classes_union)],
    ['array', () => test(iterations, array)],
  ]);
}

// expected order (fast to slow): bitflags_match_3, bitflags_classes_match_3, array_match_3
enum native_perms_enum {
  Read = 1 << 1,
  Write = 1 << 2,
  Execute = 1 << 3,
}
const native_perms_3_val =
  native_perms_enum.Read | native_perms_enum.Write | native_perms_enum.Execute;
const native_bf_match_3 = () => {
  return (native_perms_3_val & bitflags_match_3_enum.Execute) !== 0;
};
const bitflags_match_3_enum = bitFlag('Read', 'Write', 'Execute');
const bitflags_match_3_val = bitflags_match_3_enum.union(
  bitflags_match_3_enum.Read,
  bitflags_match_3_enum.Write,
  bitflags_match_3_enum.Execute
);
const bitflags_match_3 = () => {
  return bitflags_match_3_val.hasFlag(bitflags_match_3_enum.Execute);
};

const bitflags_classes_3_enum = createBitFlagsEnum([
  'Read',
  'Write',
  'Execute',
] as const);
const bitflags_classes_3_val = bitflags_classes_3_enum.Execute.or(
  bitflags_classes_3_enum.Read
).or(bitflags_classes_3_enum.Write);
const bitflags_classes_match_3 = () => {
  return bitflags_classes_3_val.hasFlag(bitflags_classes_3_enum.Execute);
};

const array_3_val = ['Read', 'Write', 'Execute'];
const array_match_3 = () => {
  return array_3_val.includes('Execute');
};

testGroup('Match a Single Flag in size-3 Union', 10, [
  ['native_bf_match_3', () => test(iterations, native_bf_match_3)],
  ['bitflags_match_3', () => test(iterations, bitflags_match_3)],
  [
    'bitflags_classes_match_3',
    () => test(iterations, bitflags_classes_match_3),
  ],
  ['array_match_3', () => test(iterations, array_match_3)],
]);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.