mirror of
https://github.com/neovim/neovim.git
synced 2026-02-04 19:42:21 +10:00
Allow Include What You Use to remove unnecessary includes and only include what is necessary. This helps with reducing compilation times and makes it easier to visualise which dependencies are actually required. Work on https://github.com/neovim/neovim/issues/549, but doesn't close it since this only works fully for .c files and not headers.
223 lines
5.2 KiB
C
223 lines
5.2 KiB
C
// This is an open source non-commercial project. Dear PVS-Studio, please check
|
|
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
|
|
|
/// @file garray.c
|
|
///
|
|
/// Functions for handling growing arrays.
|
|
|
|
#include <string.h>
|
|
|
|
#include "nvim/garray.h"
|
|
#include "nvim/log.h"
|
|
#include "nvim/memory.h"
|
|
#include "nvim/path.h"
|
|
#include "nvim/strings.h"
|
|
#include "nvim/types.h"
|
|
|
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
|
# include "garray.c.generated.h" // IWYU pragma: export
|
|
#endif
|
|
|
|
/// Clear an allocated growing array.
|
|
void ga_clear(garray_T *gap)
|
|
{
|
|
xfree(gap->ga_data);
|
|
|
|
// Initialize growing array without resetting itemsize or growsize
|
|
gap->ga_data = NULL;
|
|
gap->ga_maxlen = 0;
|
|
gap->ga_len = 0;
|
|
}
|
|
|
|
/// Clear a growing array that contains a list of strings.
|
|
///
|
|
/// @param gap
|
|
void ga_clear_strings(garray_T *gap)
|
|
{
|
|
GA_DEEP_CLEAR_PTR(gap);
|
|
}
|
|
|
|
/// Initialize a growing array.
|
|
///
|
|
/// @param gap
|
|
/// @param itemsize
|
|
/// @param growsize
|
|
void ga_init(garray_T *gap, int itemsize, int growsize)
|
|
{
|
|
gap->ga_data = NULL;
|
|
gap->ga_maxlen = 0;
|
|
gap->ga_len = 0;
|
|
gap->ga_itemsize = itemsize;
|
|
ga_set_growsize(gap, growsize);
|
|
}
|
|
|
|
/// A setter for the growsize that guarantees it will be at least 1.
|
|
///
|
|
/// @param gap
|
|
/// @param growsize
|
|
void ga_set_growsize(garray_T *gap, int growsize)
|
|
{
|
|
if (growsize < 1) {
|
|
WLOG("trying to set an invalid ga_growsize: %d", growsize);
|
|
gap->ga_growsize = 1;
|
|
} else {
|
|
gap->ga_growsize = growsize;
|
|
}
|
|
}
|
|
|
|
/// Make room in growing array "gap" for at least "n" items.
|
|
///
|
|
/// @param gap
|
|
/// @param n
|
|
void ga_grow(garray_T *gap, int n)
|
|
{
|
|
if (gap->ga_maxlen - gap->ga_len >= n) {
|
|
// the garray still has enough space, do nothing
|
|
return;
|
|
}
|
|
|
|
if (gap->ga_growsize < 1) {
|
|
WLOG("ga_growsize(%d) is less than 1", gap->ga_growsize);
|
|
}
|
|
|
|
// the garray grows by at least growsize
|
|
if (n < gap->ga_growsize) {
|
|
n = gap->ga_growsize;
|
|
}
|
|
|
|
// A linear growth is very inefficient when the array grows big. This
|
|
// is a compromise between allocating memory that won't be used and too
|
|
// many copy operations. A factor of 1.5 seems reasonable.
|
|
if (n < gap->ga_len / 2) {
|
|
n = gap->ga_len / 2;
|
|
}
|
|
|
|
int new_maxlen = gap->ga_len + n;
|
|
|
|
size_t new_size = (size_t)gap->ga_itemsize * (size_t)new_maxlen;
|
|
size_t old_size = (size_t)gap->ga_itemsize * (size_t)gap->ga_maxlen;
|
|
|
|
// reallocate and clear the new memory
|
|
char *pp = xrealloc(gap->ga_data, new_size);
|
|
memset(pp + old_size, 0, new_size - old_size);
|
|
|
|
gap->ga_maxlen = new_maxlen;
|
|
gap->ga_data = pp;
|
|
}
|
|
|
|
/// Sort "gap" and remove duplicate entries. "gap" is expected to contain a
|
|
/// list of file names in allocated memory.
|
|
///
|
|
/// @param gap
|
|
void ga_remove_duplicate_strings(garray_T *gap)
|
|
{
|
|
char **fnames = gap->ga_data;
|
|
|
|
// sort the growing array, which puts duplicates next to each other
|
|
sort_strings(fnames, gap->ga_len);
|
|
|
|
// loop over the growing array in reverse
|
|
for (int i = gap->ga_len - 1; i > 0; i--) {
|
|
if (path_fnamecmp(fnames[i - 1], fnames[i]) == 0) {
|
|
xfree(fnames[i]);
|
|
|
|
// close the gap (move all strings one slot lower)
|
|
for (int j = i + 1; j < gap->ga_len; j++) {
|
|
fnames[j - 1] = fnames[j];
|
|
}
|
|
|
|
gap->ga_len--;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// For a growing array that contains a list of strings: concatenate all the
|
|
/// strings with sep as separator.
|
|
///
|
|
/// @param gap
|
|
/// @param sep
|
|
///
|
|
/// @returns the concatenated strings
|
|
char *ga_concat_strings_sep(const garray_T *gap, const char *sep)
|
|
FUNC_ATTR_NONNULL_RET
|
|
{
|
|
const size_t nelem = (size_t)gap->ga_len;
|
|
const char **strings = gap->ga_data;
|
|
|
|
if (nelem == 0) {
|
|
return xstrdup("");
|
|
}
|
|
|
|
size_t len = 0;
|
|
for (size_t i = 0; i < nelem; i++) {
|
|
len += strlen(strings[i]);
|
|
}
|
|
|
|
// add some space for the (num - 1) separators
|
|
len += (nelem - 1) * strlen(sep);
|
|
char *const ret = xmallocz(len);
|
|
|
|
char *s = ret;
|
|
for (size_t i = 0; i < nelem - 1; i++) {
|
|
s = xstpcpy(s, strings[i]);
|
|
s = xstpcpy(s, sep);
|
|
}
|
|
strcpy(s, strings[nelem - 1]); // NOLINT(runtime/printf)
|
|
|
|
return ret;
|
|
}
|
|
|
|
/// For a growing array that contains a list of strings: concatenate all the
|
|
/// strings with a separating comma.
|
|
///
|
|
/// @param gap
|
|
///
|
|
/// @returns the concatenated strings
|
|
char_u *ga_concat_strings(const garray_T *gap) FUNC_ATTR_NONNULL_RET
|
|
{
|
|
return (char_u *)ga_concat_strings_sep(gap, ",");
|
|
}
|
|
|
|
/// Concatenate a string to a growarray which contains characters.
|
|
/// When "s" is NULL does not do anything.
|
|
///
|
|
/// WARNING:
|
|
/// - Does NOT copy the NUL at the end!
|
|
/// - The parameter may not overlap with the growing array
|
|
///
|
|
/// @param gap
|
|
/// @param s
|
|
void ga_concat(garray_T *gap, const char *restrict s)
|
|
{
|
|
if (s == NULL) {
|
|
return;
|
|
}
|
|
|
|
ga_concat_len(gap, s, strlen(s));
|
|
}
|
|
|
|
/// Concatenate a string to a growarray which contains characters
|
|
///
|
|
/// @param[out] gap Growarray to modify.
|
|
/// @param[in] s String to concatenate.
|
|
/// @param[in] len String length.
|
|
void ga_concat_len(garray_T *const gap, const char *restrict s, const size_t len)
|
|
FUNC_ATTR_NONNULL_ALL
|
|
{
|
|
if (len) {
|
|
ga_grow(gap, (int)len);
|
|
char *data = gap->ga_data;
|
|
memcpy(data + gap->ga_len, s, len);
|
|
gap->ga_len += (int)len;
|
|
}
|
|
}
|
|
|
|
/// Append one byte to a growarray which contains bytes.
|
|
///
|
|
/// @param gap
|
|
/// @param c
|
|
void ga_append(garray_T *gap, char c)
|
|
{
|
|
GA_APPEND(char, gap, c);
|
|
}
|