This lets you call back to a given function pointer if ptr is invalid. It is used primarily by windows code which wants a specialized callback.
| 703 | // This lets you call back to a given function pointer if ptr is invalid. |
| 704 | // It is used primarily by windows code which wants a specialized callback. |
| 705 | inline void* do_realloc_with_callback( |
| 706 | void* old_ptr, size_t new_size, |
| 707 | void (*invalid_free_fn)(void*), |
| 708 | size_t (*invalid_get_size_fn)(void*)) { |
| 709 | // Get the size of the old entry |
| 710 | const size_t old_size = GetSizeWithCallback(old_ptr, invalid_get_size_fn); |
| 711 | |
| 712 | // Reallocate if the new size is larger than the old size, |
| 713 | // or if the new size is significantly smaller than the old size. |
| 714 | // We do hysteresis to avoid resizing ping-pongs: |
| 715 | // . If we need to grow, grow to max(new_size, old_size * 1.X) |
| 716 | // . Don't shrink unless new_size < old_size * 0.Y |
| 717 | // X and Y trade-off time for wasted space. For now we do 1.25 and 0.5. |
| 718 | const unsigned int lower_bound_to_grow = old_size + old_size / 4; |
| 719 | const unsigned int upper_bound_to_shrink = old_size / 2; |
| 720 | if ((new_size > old_size) || (new_size < upper_bound_to_shrink)) { |
| 721 | // Need to reallocate. |
| 722 | void* new_ptr = NULL; |
| 723 | |
| 724 | if (new_size > old_size && new_size < lower_bound_to_grow) { |
| 725 | new_ptr = do_malloc(lower_bound_to_grow); |
| 726 | } |
| 727 | if (new_ptr == NULL) { |
| 728 | // Either new_size is not a tiny increment, or last do_malloc failed. |
| 729 | new_ptr = do_malloc(new_size); |
| 730 | } |
| 731 | if (new_ptr == NULL) { |
| 732 | return NULL; |
| 733 | } |
| 734 | memcpy(new_ptr, old_ptr, ((old_size < new_size) ? old_size : new_size)); |
| 735 | // We could use a variant of do_free() that leverages the fact |
| 736 | // that we already know the sizeclass of old_ptr. The benefit |
| 737 | // would be small, so don't bother. |
| 738 | do_free_with_callback(old_ptr, invalid_free_fn); |
| 739 | return new_ptr; |
| 740 | } else { |
| 741 | return old_ptr; |
| 742 | } |
| 743 | } |
| 744 | |
| 745 | inline void* do_realloc(void* old_ptr, size_t new_size) { |
| 746 | return do_realloc_with_callback(old_ptr, new_size, |
no test coverage detected