int main(void) { struct permutation *pi; int single = 12345; char pair[] = { 'P', 'Q' }; uint16_t triple[] = {7, 9, 1000}; word four[] = {"ZERO", "ONE", "TWO", "THREE"}; int i; plan_tests(2 * permutation_count(1) + 1 + 2 * permutation_count(2) + 1 + 2 * permutation_count(3) + 1 + 2 * permutation_count(4) + 1 + MAX_ITEMS + 1); /* One */ pi = permutation_new(1); CHECK_ORDER(&single, int, 12345); ok1(!permutation_change_array(pi, &single, sizeof(single))); CHECK_ORDER(&single, int, 12345); free(pi); /* Pair */ pi = PERMUTATION_NEW(pair); CHECK_ORDER(pair, char, 'P', 'Q'); PERMUTE(pi, pair); CHECK_ORDER(pair, char, 'Q', 'P'); ok1(!PERMUTATION_CHANGE_ARRAY(pi, pair)); CHECK_ORDER(pair, char, 'Q', 'P'); free(pi); /* Triple */ pi = PERMUTATION_NEW(triple); CHECK_ORDER(triple, uint16_t, 7, 9, 1000); PERMUTE(pi, triple); CHECK_ORDER(triple, uint16_t, 7, 1000, 9); PERMUTE(pi, triple); CHECK_ORDER(triple, uint16_t, 1000, 7, 9); PERMUTE(pi, triple); CHECK_ORDER(triple, uint16_t, 1000, 9, 7); PERMUTE(pi, triple); CHECK_ORDER(triple, uint16_t, 9, 1000, 7); PERMUTE(pi, triple); CHECK_ORDER(triple, uint16_t, 9, 7, 1000); ok1(!PERMUTATION_CHANGE_ARRAY(pi, triple)); CHECK_ORDER(triple, uint16_t, 9, 7, 1000); free(pi); /* Four */ pi = PERMUTATION_NEW(four); CHECK_ORDER(four, word, "ZERO", "ONE", "TWO", "THREE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ZERO", "ONE", "THREE", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ZERO", "THREE", "ONE", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "ZERO", "ONE", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "ZERO", "TWO", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ZERO", "THREE", "TWO", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ZERO", "TWO", "THREE", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ZERO", "TWO", "ONE", "THREE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "ZERO", "ONE", "THREE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "ZERO", "THREE", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "THREE", "ZERO", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "TWO", "ZERO", "ONE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "TWO", "ONE", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "THREE", "ONE", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "ONE", "THREE", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "TWO", "ONE", "ZERO", "THREE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "TWO", "ZERO", "THREE"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "TWO", "THREE", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "THREE", "TWO", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "ONE", "TWO", "ZERO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "THREE", "ONE", "ZERO", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "THREE", "ZERO", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "ZERO", "THREE", "TWO"); PERMUTE(pi, four); CHECK_ORDER(four, word, "ONE", "ZERO", "TWO", "THREE"); ok1(!PERMUTATION_CHANGE_ARRAY(pi, four)); CHECK_ORDER(four, word, "ONE", "ZERO", "TWO", "THREE"); free(pi); for (i = 0; i <= MAX_ITEMS; i++) { uint64_t nperms = 1; diag("Counting permutations of %d\n", i); pi = permutation_new(i); while (permutation_change(pi)) nperms++; ok(nperms == permutation_count(i), "%"PRId64" permutations of %d (%d! == %lld)", nperms, i, i, permutation_count(i)); free(pi); } /* This exits depending on whether all tests passed */ return exit_status(); }
/** * @internal * Decode a ordered register list from the 10 bit register encoding as defined by the CFE format. * * @param permutation The 10-bit encoded register list. * @param count The number of registers to decode from @a permutation. * @param registers On return, the ordered list of decoded register values. These values must correspond to the CFE * register values, <em>not</em> the register values as defined in the PLCrashReporter thread state APIs. * * @warning This API is unlikely to be useful outside the CFE encoder implementation, and should not generally be used. * Callers must be careful to pass only literal register values defined in the CFE format (eg, values 1-6). */ void apigee_plcrash_async_cfe_register_decode (uint32_t permutation, uint32_t count, uint32_t registers[]) { PLCF_ASSERT(count <= PLCRASH_ASYNC_CFE_SAVED_REGISTER_MAX); /* * Each register is encoded by mapping the values to a 10-bit range, and then further sub-ranges within that range, * with a subrange allocated to each position. See the encoding function for full documentation. */ int permunreg[PLCRASH_ASYNC_CFE_SAVED_REGISTER_MAX]; #define PERMUTE(pos, factor) do { \ permunreg[pos] = permutation/factor; \ permutation -= (permunreg[pos]*factor); \ } while (0) PLCF_ASSERT(PLCRASH_ASYNC_CFE_SAVED_REGISTER_MAX == 6); switch (count) { case 6: PERMUTE(0, 120); PERMUTE(1, 24); PERMUTE(2, 6); PERMUTE(3, 2); PERMUTE(4, 1); /* * There are 6 elements in the list, 6 possible values for each element, and values may not repeat. The * value of the last element can be derived from the values previously seen (and due to the positional * renumbering performed, the value of the last element will *always* be 0). */ permunreg[5] = 0; break; case 5: PERMUTE(0, 120); PERMUTE(1, 24); PERMUTE(2, 6); PERMUTE(3, 2); PERMUTE(4, 1); break; case 4: PERMUTE(0, 60); PERMUTE(1, 12); PERMUTE(2, 3); PERMUTE(3, 1); break; case 3: PERMUTE(0, 20); PERMUTE(1, 4); PERMUTE(2, 1); break; case 2: PERMUTE(0, 5); PERMUTE(1, 1); break; case 1: PERMUTE(0, 1); break; } #undef PERMUTE /* Recompute the actual register values based on the position-relative values. */ bool position_used[PLCRASH_ASYNC_CFE_SAVED_REGISTER_MAX+1] = { 0 }; for (uint32_t i = 0; i < count; ++i) { int renumbered = 0; for (int u = 1; u < 7; u++) { if (!position_used[u]) { if (renumbered == permunreg[i]) { registers[i] = u; position_used[u] = true; break; } renumbered++; } } } }