Hash :
5346be3d
Author :
Date :
2021-09-23T21:16:36
Any library needs to take data from users, and then return data to
users. With some types this is simple - integer parameters and return
types are trivial. But with more complex data types, things are more
complicated. Even something seemingly simple, like a C string, requires
discipline: we cannot simple return an allocated hunk of memory for
callers to free
, since some systems have multiple allocators and users
cannot necessarily reason about the allocator used and which corresponding
deallocation function to call to free the memory.
Most types in libgit2 are “opaque” types, which we treat as “objects” (even
though C is “not an object oriented language”). You may create an object -
for example, with git_odb_new
, or libgit2 may return you an object as an
“out” parameter - for example, with git_repository_open
. With any of
these objects, you should call their corresponding _free
function (for
example, git_odb_free
or git_repository_free
) when you are done using
them.
libgit2 will often take input as structures (for example, options
structures like git_merge_options
). Rarely, libgit2 will return data in
a structure. This is typically used for simpler data types, like git_buf
and git_strarray
. Users should allocate the structure themselves (either
on the stack or the heap) and pass a pointer to it. Since libgit2 does not
allocate the structure itself, only the data inside of it, the deallocation
functions are suffixed with _dispose
instead of _free
, since they only
free the data inside the structure.
git_buf
)
libgit2 typically takes NUL-terminated strings (“C strings”) with a
const char *
, and typically takes raw data with a const char *
and a
corresponding size_t
for its size. libgit2 typically returns strings
or raw data in a git_buf
structure. The given data buffer will always be
NUL terminated (even if it contains binary data) and the size
member will
always contain the size (in bytes) of the contents of the pointer (excluding
the NUL terminator).
In other words, if a git_buf
contains the string foo
then the memory
buffer will be { f
, o
, o
, \0
} and the size will be 3
.
Callers must initialize the buffer with GIT_BUF_INIT
(or by setting
all the members to 0
) when it is created, before passing a pointer
to the buffer to libgit2 for the first time.
Subsequent calls to libgit2 APIs that take a buffer can re-use a buffer that was previously used. The buffer will be cleared and grown to accommodate the new contents (if necessary). The new data will written into the buffer, overwriting the previous contents. This allows callers to reduce the number of allocations performed by the library.
Callers must call git_buf_dispose
when they have finished.
Note that the deprecated git_diff_format_email
API does not follow
this behavior; subsequent calls will concatenate data to the buffer
instead of rewriting it. Users should move to the new git_email
APIs that follow the git_buf
standards.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
Memory allocation and ownership
-------------------------------
Any library needs to _take_ data from users, and then _return_ data to
users. With some types this is simple - integer parameters and return
types are trivial. But with more complex data types, things are more
complicated. Even something seemingly simple, like a C string, requires
discipline: we cannot simple return an allocated hunk of memory for
callers to `free`, since some systems have multiple allocators and users
cannot necessarily reason about the allocator used and which corresponding
deallocation function to call to free the memory.
## Objects
Most types in libgit2 are "opaque" types, which we treat as "objects" (even
though C is "not an object oriented language"). You may create an object -
for example, with `git_odb_new`, or libgit2 may return you an object as an
"out" parameter - for example, with `git_repository_open`. With any of
these objects, you should call their corresponding `_free` function (for
example, `git_odb_free` or `git_repository_free`) when you are done using
them.
## Structures
libgit2 will often take _input_ as structures (for example, options
structures like `git_merge_options`). Rarely, libgit2 will return data in
a structure. This is typically used for simpler data types, like `git_buf`
and `git_strarray`. Users should allocate the structure themselves (either
on the stack or the heap) and pass a pointer to it. Since libgit2 does not
allocate the structure itself, only the data inside of it, the deallocation
functions are suffixed with `_dispose` instead of `_free`, since they only
free the data _inside_ the structure.
## Strings or continuous memory buffers (`git_buf`)
libgit2 typically _takes_ NUL-terminated strings ("C strings") with a
`const char *`, and typically _takes_ raw data with a `const char *` and a
corresponding `size_t` for its size. libgit2 typically _returns_ strings
or raw data in a `git_buf` structure. The given data buffer will always be
NUL terminated (even if it contains binary data) and the `size` member will
always contain the size (in bytes) of the contents of the pointer (excluding
the NUL terminator).
In other words, if a `git_buf` contains the string `foo` then the memory
buffer will be { `f`, `o`, `o`, `\0` } and the size will be `3`.
Callers _must_ initialize the buffer with `GIT_BUF_INIT` (or by setting
all the members to `0`) when it is created, before passing a pointer
to the buffer to libgit2 for the first time.
Subsequent calls to libgit2 APIs that take a buffer can re-use a
buffer that was previously used. The buffer will be cleared and grown
to accommodate the new contents (if necessary). The new data will
written into the buffer, overwriting the previous contents. This
allows callers to reduce the number of allocations performed by the
library.
Callers must call `git_buf_dispose` when they have finished.
Note that the deprecated `git_diff_format_email` API does not follow
this behavior; subsequent calls will concatenate data to the buffer
instead of rewriting it. Users should move to the new `git_email`
APIs that follow the `git_buf` standards.