Skip to content

Instantly share code, notes, and snippets.

@pichi
Last active December 30, 2015 22:09
Show Gist options
  • Save pichi/7892725 to your computer and use it in GitHub Desktop.
Save pichi/7892725 to your computer and use it in GitHub Desktop.
Generating "binary code" (see http://stackoverflow.com/q/20422126/49197)
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
enum {
max_k = 6, // it can't be bigger than 6 because it has to fit in 64 bit set
};
typedef uint64_t set;
typedef unsigned char number; // 1 << max_k has to fit
static inline set set_n(set set, number n) { return set | (1ULL << n); }
static inline int is_set(set set, number n) { return (set & (1ULL << n)) != 0; }
static inline char *num2str(char *s, int k, number n) {
unsigned char *end = s += k;
*s-- = 0; // terminate string, just for debugging and doesn't matter
for(; k; k--, n >>= 1)
*s-- = '0' + (n & 1); // make '0'/'1' string backwards
return end;
}
// unsafe - doesn't add terminator, calloc does
static inline char *add_zero(char *s) { *s++ = '0'; return s; }
static inline char *add_one(char *s) { *s++ = '1'; return s; }
static inline number combs(int k) { return 1 << k; }
static inline number max_comb(int k) { return combs(k) - 1; }
static inline size_t codelen(int k) { return combs(k) + k - 1; }
static void gen(int k) {
char *code = calloc(codelen(k) + 1, sizeof(char));
set s = 0;
number n, mask = max_comb(k); // max_comb(k) is mask with k set bits
// buf points to position in current code
void gen_(char *buf, set s, int rest, number x) {
if(rest) {
x = (x << 1) & mask;
if(!is_set(s, x))
gen_(add_zero(buf), set_n(s, x), rest - 1, x);
x |= 1;
if(!is_set(s, x))
gen_(add_one(buf), set_n(s, x), rest - 1, x);
}
else { // done, assume calloc clears memory so terminator is already there
puts(code);
}
}
for(n = 0; n < combs(k); n++)
gen_(num2str(code, k, n), set_n(s, n), combs(k) - 1, n);
free(code);
}
int usage(const char *name) {
fprintf(stderr, "Usage: %s k\n\nk has to be number from 1 up to %d\n", name, max_k);
return EXIT_FAILURE;
}
int main(int argc, const char* argv[] ) {
const char *name = argv[0];
char *tmp, str[10];
int i;
if(argc != 2) return usage(name);
i = strtol(argv[1], &tmp, 10);
if(*tmp != '\0' || i < 1 || i > max_k) return usage(name);
gen(i);
return EXIT_SUCCESS;
}
@pichi
Copy link
Author

pichi commented Dec 10, 2013

First version is attempt to solve it without recursion. But gcc seems doing amazing work to optimize recursive code so recursive version is about 10% faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment