<commit_before>/*

Package gomempool implements a simple memory pool for byte slices.

When To Use gomempool

The Go garbage collector runs more often when more bytes are allocated.
(For full details, see the runtime package documentation on the GOGC
variable.) Avoiding allocations can help the stop-the-world GC run
much less often.

Consider using gomempool if your code is allocating many []byte slices,
and triggering many garbage collection pauses as a result. I strongly
suggest determining this via consulting runtime.ReadMemStats to ensure
this is the real problem before using gomempool. gomempool is a power
tool; it can save your program, but it can blow your feet off, too.
(I've done both.)

Using Gomempool

To use the pool, there are three basic steps:

 1. Create a pool
 2. Obtain byte slices
 3. Optionally return the byte slices

In addition to this documentation, be sure to open the Example below for
a code example.

Create A Pool

A *Pool is obtained by calling gomempool.New. All methods on the *Pool are
threadsafe. The pool can be configured via the New call.

A nil pointer of type *gomempool.Pool is also a valid pool. This will
use normal make() to create byte slices and simply discard the slice
when asked to .Return() it.

Obtain byte slices

[]bytes in the pool come with an "Allocator" that is responsible for
returning them correctly.

To obtain an allocator, you call GetNewAllocator() on the pool. This
returns an allocator that is not yet used. You may then call
.Allocate(uint64) on it to assign a []byte from the pool. This []byte
is then associated with that Allocator until you call .Return() on
the allocator, after which the []byte goes back into the pool.

You MUST NOT call .Return() until you are entirely done with the []byte.
This includes shared slices you may have created; this is by far the
easiest way to get in trouble with a []byte pool, as it is easy to
accidentally introduce sharing without realizing it.

You must also make sure not to do anything with your []byte that might
cause another []byte to be created instead; for instance, using
your pooled []byte in an "append" call is dangerous, because the runtime
might decide to give you back a []byte that backs to an entirely
different array. In this case your []byte and your Allocator will
cease to be related. If the Allocator is correctly managed, your code
will not fail, but you won't be getting any benefit, either.

You may retrieve the []byte slice corresponding to an Allocator at any
time by calling .Bytes(). This means that if you do need to pass the
[]byte and Allocator around, it suffices to pass just the Allocator.
(Though, be aware that the Allocator's []byte will be of the original
size you asked for. This can not be changed, as you can not change the
original slice itself.)

Once allocated, an allocator will PANIC if you try to allocate again with
ErrBytesAlreadyAllocated.

Once .Return() has been called, an allocator will PANIC if you try to
.Return() the []byte again.

If no []byte is currently allocated, .Bytes() will PANIC if called.

This is fully on purpose. All of these situations represent profound
errors in your code. This sort of error is just as dangerous in Go
as it is in any other language. Go may not segfault, but memory
management issues can still dish out the pain; better to find out
earlier rather than later.

You can combine obtaining an Allocator and a particular sized []byte
by calling .Allocate() on the pool.

Allocators can be reused freely, as long as they are used correctly.
However, an individual Allocator is not threadsafe. Its interaction
with the Pool is, but its internal values are not; do not use the
same Allocator from more than one goroutine at a time.

The Allocators returned by the nil *Pool use make() to create new
slices every time, and simply discard the []byte when done, but they
enforce the exact same rules as the "real" Allocators, and panic
in all the same places. This is so there is as little difference as
possible between the two types of pools.

Optionally return the byte slices

Calling .Return() on an allocator is optional. If a []byte is not
returned to the pool, you do not get any further benefit from the pool
for that []byte, but the garbage collector will still clean it up
normally. This means using a pool is still feasible even if some of
your code paths may need to retain a []byte for a long or complicated
period of time.

Additional Functionality

You can query the pool for its cache statistics by calling Stats(),
which will return a structure describing how the individual buckets
are performing.

Quality: At the moment I would call this alpha code. Go lint clean, go vet<commit_msg>Further tune the documentation.<commit_after>/*

Package gomempool implements a simple memory pool for byte slices.

When To Use gomempool

The Go garbage collector runs more often when more bytes are allocated.
(For full details, see the runtime package documentation on the GOGC
variable.) Avoiding allocations can help the stop-the-world GC run
much less often.

Consider using gomempool if your code is allocating many []byte slices,
and triggering many garbage collection pauses as a result. I strongly
suggest determining this via consulting runtime.ReadMemStats to ensure
this is the real problem before using gomempool. gomempool is a power
tool; it can save your program, but it can blow your feet off, too.
(I've done both.)

Using Gomempool

To use the pool, there are three basic steps:

 1. Create a pool
 2. Obtain byte slices
 3. Optionally return the byte slices

See the Example below for concise usage examples.

Create A Pool

First, create a pool.

    pool := gomempool.New(
            64,          // minimum sized slice to hand out
            1024 * 1024, // maximum sized slice to hand out
            10,          // maximum number of buffers to save
        )

A *Pool is obtained by calling gomempool.New. All methods on the *Pool are
threadsafe. The pool can be configured via the New call.

    var pool *gomempool.Pool

A nil pointer of type *gomempool.Pool is also a valid pool. This will
use normal make() to create byte slices and simply discard the slice
when asked to .Return() it. This is convenient for testing whether
you've got a memory error in your code, because you can swap in a nil
Pool pointer without changing any other code. If an error goes away
when you do that, you have a memory error. (Probably .Return()ing
something too soon.)

Obtain byte slices

[]bytes in the pool come with an "Allocator" that is responsible for
returning them correctly.

    allocator := pool.GetNewAllocator()
    bytes := allocator.Allocate(453)

    // use the bytes

To obtain an allocator, you call GetNewAllocator() on the pool. This
returns an allocator that is not yet used. You may then call
.Allocate(uint64) on it to assign a []byte from the pool. This []byte
is then associated with that Allocator until you call .Return() on
the allocator, after which the []byte goes back into the pool.

You MUST NOT call .Return() until you are entirely done with the []byte.
This includes shared slices you may have created; this is by far the
easiest way to get in trouble with a []byte pool, as it is easy to
accidentally introduce sharing without realizing it.

You must also make sure not to do anything with your []byte that might
cause another []byte to be created instead; for instance, using
your pooled []byte in an "append" call is dangerous, because the runtime
might decide to give you back a []byte that backs to an entirely
different array. In this case your []byte and your Allocator will
cease to be related. If the Allocator is correctly managed, your code
will not fail, but you won't be getting any benefit, either.

    allocator2 := pool.GetNewAllocator()
    allocator2.Allocate(738)
    newBytes := allocator.Bytes()

You may retrieve the []byte slice corresponding to an Allocator at any
time by calling .Bytes(). This means that if you do need to pass the
[]byte and Allocator around, it suffices to pass just the Allocator.
(Though, be aware that the Allocator's []byte will be of the original
size you asked for. This can not be changed, as you can not change the
original slice itself.)

Allocators can be reused freely, as long as they are used correctly.
However, an individual Allocator is not threadsafe. Its interaction
with the Pool is, but its internal values are not; do not use the
same Allocator from more than one goroutine at a time.

    // using the same allocator as above
    allocator2.Allocate(723) // PANIC!

Once allocated, an allocator will PANIC if you try to allocate again with
ErrBytesAlreadyAllocated.

Once .Return() has been called, an allocator will PANIC if you try to
.Return() the []byte again.

If no []byte is currently allocated, .Bytes() will PANIC if called.

This is fully on purpose. All of these situations represent profound
errors in your code. This sort of error is just as dangerous in Go
as it is in any other language. Go may not segfault, but memory
management issues can still dish out the pain; better to find out
earlier rather than later.

    thirdBytes, newAllocator := pool.Allocate(23314)

You can combine obtaining an Allocator and a particular sized []byte
by calling .Allocate() on the pool.

The Allocators returned by the nil *Pool use make() to create new
slices every time, and simply discard the []byte when done, but they
enforce the exact same rules as the "real" Allocators, and panic
in all the same places. This is so there is as little difference as
possible between the two types of pools.

Optionally return the byte slices

    bytes, allocator := pool.Allocate(29348)
    defer allocator.Return()
    // use bytes

Calling .Return() on an allocator is optional. If a []byte is not
returned to the pool, you do not get any further benefit from the pool
for that []byte, but the garbage collector will still clean it up
normally. This means using a pool is still feasible even if some of
your code paths may need to retain a []byte for a long or complicated
period of time.

Additional Functionality

You can query the pool for its cache statistics by calling Stats(),
which will return a structure describing how the individual buckets
are performing.

Quality: At the moment I would call this alpha code. Go lint clean, go vet
{'fraction_non_alphanumeric': 0.04592821304515631, 'fraction_numerical': 0.0042454650714010035, 'mean_word_length': 3.978386167146974, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5635298', 'n_tokens_mistral': 2752, 'n_tokens_neox': 2629, 'n_words': 1714}