static bool state_manager_pop(state_manager_t *state, const void **data) { size_t start; uint8_t *out = NULL; const uint8_t *compressed = NULL; *data = NULL; if (state->thisblock_valid) { state->thisblock_valid = false; state->entries--; *data = state->thisblock; return true; } if (state->head == state->tail) return false; start = read_size_t(state->head - sizeof(size_t)); state->head = state->data + start; compressed = state->data + start + sizeof(size_t); out = state->thisblock; state_manager_raw_decompress(compressed, state->maxcompsize, out, state->blocksize); state->entries--; *data = state->thisblock; return true; }
bool state_manager_pop(state_manager_t *state, const void **data) { size_t start; uint8_t *out; uint16_t *out16; const uint8_t *compressed = NULL; const uint16_t *compressed16 = NULL; *data = NULL; if (state->thisblock_valid) { state->thisblock_valid = false; state->entries--; *data = state->thisblock; return true; } if (state->head == state->tail) return false; start = read_size_t(state->head - sizeof(size_t)); state->head = state->data + start; compressed = state->data + start + sizeof(size_t); out = state->thisblock; /* Begin decompression code * out is the last pushed (or returned) state */ compressed16 = (const uint16_t*)compressed; out16 = (uint16_t*)out; for (;;) { uint16_t i; uint16_t numchanged = *(compressed16++); if (numchanged) { out16 += *compressed16++; /* We could do memcpy, but it seems that memcpy has a * constant-per-call overhead that actually shows up. * * Our average size in here seems to be 8 or something. * Therefore, we do something with lower overhead. */ for (i = 0; i < numchanged; i++) out16[i] = compressed16[i]; compressed16 += numchanged; out16 += numchanged; } else { uint32_t numunchanged = compressed16[0] | (compressed16[1] << 16); if (!numunchanged) break; compressed16 += 2; out16 += numunchanged; } } /* End decompression code */ state->entries--; *data = state->thisblock; return true; }
static void state_manager_push_do(state_manager_t *state) { #if STRICT_BUF_SIZE memcpy(state->nextblock, state->debugblock, state->debugsize); #endif static struct retro_perf_counter gen_deltas = {0}; uint8_t *swap = NULL; if (state->thisblock_valid) { const uint8_t *oldb, *newb; uint8_t *compressed; size_t headpos, tailpos, remaining; if (state->capacity < sizeof(size_t) + state->maxcompsize) return; recheckcapacity:; headpos = state->head - state->data; tailpos = state->tail - state->data; remaining = (tailpos + state->capacity - sizeof(size_t) - headpos - 1) % state->capacity + 1; if (remaining <= state->maxcompsize) { state->tail = state->data + read_size_t(state->tail); state->entries--; goto recheckcapacity; } performance_counter_init(&gen_deltas, "gen_deltas"); performance_counter_start(&gen_deltas); oldb = state->thisblock; newb = state->nextblock; compressed = state->head + sizeof(size_t); compressed += state_manager_raw_compress(oldb, newb, state->blocksize, compressed); if (compressed - state->data + state->maxcompsize > state->capacity) { compressed = state->data; if (state->tail == state->data + sizeof(size_t)) state->tail = state->data + read_size_t(state->tail); } write_size_t(compressed, state->head-state->data); compressed += sizeof(size_t); write_size_t(state->head, compressed-state->data); state->head = compressed; performance_counter_stop(&gen_deltas); } else state->thisblock_valid = true; swap = state->thisblock; state->thisblock = state->nextblock; state->nextblock = swap; state->entries++; }