diff --git a/crates/generate/src/templates/array.h b/crates/generate/src/templates/array.h index a17a574f..e99918e5 100644 --- a/crates/generate/src/templates/array.h +++ b/crates/generate/src/templates/array.h @@ -52,67 +52,91 @@ extern "C" { /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is /// less than the array's current capacity, this function has no effect. -#define array_reserve(self, new_capacity) \ - _array__reserve((Array *)(self), array_elem_size(self), new_capacity) +#define array_reserve(self, new_capacity) \ + ((self)->contents = _array__reserve( \ + (void *)(self)->contents, &(self)->capacity, \ + array_elem_size(self), new_capacity) \ + ) /// Free any memory allocated for this array. Note that this does not free any /// memory allocated for the array's contents. -#define array_delete(self) _array__delete((Array *)(self)) +#define array_delete(self) _array__delete((self), (void *)(self)->contents, sizeof(*self)) /// Push a new `element` onto the end of the array. -#define array_push(self, element) \ - (_array__grow((Array *)(self), 1, array_elem_size(self)), \ - (self)->contents[(self)->size++] = (element)) +#define array_push(self, element) \ + do { \ + (self)->contents = _array__grow( \ + (void *)(self)->contents, (self)->size, &(self)->capacity, \ + 1, array_elem_size(self) \ + ); \ + (self)->contents[(self)->size++] = (element); \ + } while(0) /// Increase the array's size by `count` elements. /// New elements are zero-initialized. -#define array_grow_by(self, count) \ - do { \ - if ((count) == 0) break; \ - _array__grow((Array *)(self), count, array_elem_size(self)); \ +#define array_grow_by(self, count) \ + do { \ + if ((count) == 0) break; \ + (self)->contents = _array__grow( \ + (self)->contents, (self)->size, &(self)->capacity, \ + count, array_elem_size(self) \ + ); \ memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ - (self)->size += (count); \ + (self)->size += (count); \ } while (0) /// Append all elements from one array to the end of another. -#define array_push_all(self, other) \ +#define array_push_all(self, other) \ array_extend((self), (other)->size, (other)->contents) /// Append `count` elements to the end of the array, reading their values from the /// `contents` pointer. -#define array_extend(self, count, contents) \ - _array__splice( \ - (Array *)(self), array_elem_size(self), (self)->size, \ - 0, count, contents \ +#define array_extend(self, count, other_contents) \ + (self)->contents = _array__splice( \ + (void*)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), (self)->size, 0, count, other_contents \ ) /// Remove `old_count` elements from the array starting at the given `index`. At /// the same index, insert `new_count` new elements, reading their values from the /// `new_contents` pointer. -#define array_splice(self, _index, old_count, new_count, new_contents) \ - _array__splice( \ - (Array *)(self), array_elem_size(self), _index, \ - old_count, new_count, new_contents \ +#define array_splice(self, _index, old_count, new_count, new_contents) \ + (self)->contents = _array__splice( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), _index, old_count, new_count, new_contents \ ) /// Insert one `element` into the array at the given `index`. -#define array_insert(self, _index, element) \ - _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) +#define array_insert(self, _index, element) \ + (self)->contents = _array__splice( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), _index, 0, 1, &(element) \ + ) /// Remove one element from the array at the given `index`. #define array_erase(self, _index) \ - _array__erase((Array *)(self), array_elem_size(self), _index) + _array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index) /// Pop the last element off the array, returning the element by value. #define array_pop(self) ((self)->contents[--(self)->size]) /// Assign the contents of one array to another, reallocating if necessary. -#define array_assign(self, other) \ - _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) +#define array_assign(self, other) \ + (self)->contents = _array__assign( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + (const void *)(other)->contents, (other)->size, array_elem_size(self) \ + ) /// Swap one array with another -#define array_swap(self, other) \ - _array__swap((Array *)(self), (Array *)(other)) +#define array_swap(self, other) \ + do { \ + struct Swap swapped_contents = _array__swap( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + (void *)(other)->contents, &(other)->size, &(other)->capacity \ + ); \ + (self)->contents = swapped_contents.self_contents; \ + (other)->contents = swapped_contents.other_contents; \ + } while (0) /// Get the size of the array contents #define array_elem_size(self) (sizeof *(self)->contents) @@ -157,82 +181,112 @@ extern "C" { // Private -typedef Array(void) Array; +// Pointers to individual `Array` fields (rather than the entire `Array` itself) +// are passed to the various `_array__*` functions below to address strict aliasing +// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`. +// +// The `Array` type itself was not altered as a solution in order to avoid breakage +// with existing consumers (in particular, parsers with external scanners). /// This is not what you're looking for, see `array_delete`. -static inline void _array__delete(Array *self) { - if (self->contents) { - ts_free(self->contents); - self->contents = NULL; - self->size = 0; - self->capacity = 0; - } +static inline void _array__delete(void *self, void *contents, size_t self_size) { + if (contents) ts_free(contents); + if (self) memset(self, 0, self_size); } /// This is not what you're looking for, see `array_erase`. -static inline void _array__erase(Array *self, size_t element_size, - uint32_t index) { - assert(index < self->size); - char *contents = (char *)self->contents; +static inline void _array__erase(void* self_contents, uint32_t *size, + size_t element_size, uint32_t index) { + assert(index < *size); + char *contents = (char *)self_contents; memmove(contents + index * element_size, contents + (index + 1) * element_size, - (self->size - index - 1) * element_size); - self->size--; + (*size - index - 1) * element_size); + (*size)--; } /// This is not what you're looking for, see `array_reserve`. -static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { - if (new_capacity > self->capacity) { - if (self->contents) { - self->contents = ts_realloc(self->contents, new_capacity * element_size); +static inline void *_array__reserve(void *contents, uint32_t *capacity, + size_t element_size, uint32_t new_capacity) { + void *new_contents = contents; + if (new_capacity > *capacity) { + if (contents) { + new_contents = ts_realloc(contents, new_capacity * element_size); } else { - self->contents = ts_malloc(new_capacity * element_size); + new_contents = ts_malloc(new_capacity * element_size); } - self->capacity = new_capacity; + *capacity = new_capacity; } + return new_contents; } /// This is not what you're looking for, see `array_assign`. -static inline void _array__assign(Array *self, const Array *other, size_t element_size) { - _array__reserve(self, element_size, other->size); - self->size = other->size; - memcpy(self->contents, other->contents, self->size * element_size); +static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity, + const void *other_contents, uint32_t other_size, size_t element_size) { + void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size); + *self_size = other_size; + memcpy(new_contents, other_contents, *self_size * element_size); + return new_contents; } +struct Swap { + void *self_contents; + void *other_contents; +}; + /// This is not what you're looking for, see `array_swap`. -static inline void _array__swap(Array *self, Array *other) { - Array swap = *other; - *other = *self; - *self = swap; +// static inline void _array__swap(Array *self, Array *other) { +static inline struct Swap _array__swap(void *self_contents, uint32_t *self_size, uint32_t *self_capacity, + void *other_contents, uint32_t *other_size, uint32_t *other_capacity) { + void *new_self_contents = other_contents; + uint32_t new_self_size = *other_size; + uint32_t new_self_capacity = *other_capacity; + + void *new_other_contents = self_contents; + *other_size = *self_size; + *other_capacity = *self_capacity; + + *self_size = new_self_size; + *self_capacity = new_self_capacity; + + struct Swap out = { + .self_contents = new_self_contents, + .other_contents = new_other_contents, + }; + return out; } /// This is not what you're looking for, see `array_push` or `array_grow_by`. -static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { - uint32_t new_size = self->size + count; - if (new_size > self->capacity) { - uint32_t new_capacity = self->capacity * 2; +static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity, + uint32_t count, size_t element_size) { + void *new_contents = contents; + uint32_t new_size = size + count; + if (new_size > *capacity) { + uint32_t new_capacity = *capacity * 2; if (new_capacity < 8) new_capacity = 8; if (new_capacity < new_size) new_capacity = new_size; - _array__reserve(self, element_size, new_capacity); + new_contents = _array__reserve(contents, capacity, element_size, new_capacity); } + return new_contents; } /// This is not what you're looking for, see `array_splice`. -static inline void _array__splice(Array *self, size_t element_size, +static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity, + size_t element_size, uint32_t index, uint32_t old_count, uint32_t new_count, const void *elements) { - uint32_t new_size = self->size + new_count - old_count; + uint32_t new_size = *size + new_count - old_count; uint32_t old_end = index + old_count; uint32_t new_end = index + new_count; - assert(old_end <= self->size); + assert(old_end <= *size); - _array__reserve(self, element_size, new_size); + void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size); - char *contents = (char *)self->contents; - if (self->size > old_end) { + char *contents = (char *)new_contents; + if (*size > old_end) { memmove( contents + new_end * element_size, contents + old_end * element_size, - (self->size - old_end) * element_size + (*size - old_end) * element_size ); } if (new_count > 0) { @@ -250,7 +304,9 @@ static inline void _array__splice(Array *self, size_t element_size, ); } } - self->size += new_count - old_count; + *size += new_count - old_count; + + return new_contents; } /// A binary search routine, based on Rust's `std::slice::binary_search_by`. diff --git a/crates/xtask/src/fetch.rs b/crates/xtask/src/fetch.rs index 6fa431c6..66a5862e 100644 --- a/crates/xtask/src/fetch.rs +++ b/crates/xtask/src/fetch.rs @@ -1,19 +1,74 @@ -use crate::{bail_on_err, root_dir, FetchFixtures, EMSCRIPTEN_VERSION}; +use crate::{bail_on_err, root_dir, EMSCRIPTEN_VERSION}; use anyhow::Result; -use std::{fs, process::Command}; +use std::{fs, path::Path, process::Command}; -pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { +enum FixtureRef<'a> { + Tag(&'a str), + Branch(&'a str), +} + +impl<'a> FixtureRef<'a> { + #[allow(clippy::use_self)] + const fn new(tag: &'a str, branch: Option<&'a str>) -> FixtureRef<'a> { + if let Some(b) = branch { + Self::Branch(b) + } else { + Self::Tag(tag) + } + } + + const fn ref_type(&self) -> &'static str { + match self { + FixtureRef::Tag(_) => "tag", + FixtureRef::Branch(_) => "branch", + } + } +} + +impl std::fmt::Display for FixtureRef<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FixtureRef::Tag(tag) => write!(f, "{tag}"), + FixtureRef::Branch(branch) => write!(f, "{branch}"), + } + } +} + +fn current_ref_name(grammar_dir: &Path) -> Result<(String, Option<&'static str>)> { + let tag_args = ["describe", "--tags", "--exact-match", "HEAD"]; + let branch_args = ["rev-parse", "--abbrev-ref", "HEAD"]; + + for (args, ref_type) in [tag_args.as_ref(), branch_args.as_ref()] + .iter() + .zip(&["tag", "branch"]) + { + let name_cmd = Command::new("git") + .current_dir(grammar_dir) + .args(*args) + .output()?; + let name = String::from_utf8_lossy(&name_cmd.stdout); + let name = name.trim(); + if !name.is_empty() { + return Ok((name.to_string(), Some(ref_type))); + } + } + + Ok(("".to_string(), None)) +} + +pub fn run_fixtures() -> Result<()> { let fixtures_dir = root_dir().join("test").join("fixtures"); let grammars_dir = fixtures_dir.join("grammars"); let fixtures_path = fixtures_dir.join("fixtures.json"); - // grammar name, tag - let mut fixtures: Vec<(String, String)> = + // grammar name, tag, [branch] + let fixtures: Vec<(String, String, Option)> = serde_json::from_str(&fs::read_to_string(&fixtures_path)?)?; - for (grammar, tag) in &mut fixtures { - let grammar_dir = grammars_dir.join(&grammar); + for (grammar, tag, branch) in &fixtures { + let grammar_dir = grammars_dir.join(grammar); let grammar_url = format!("https://github.com/tree-sitter/tree-sitter-{grammar}"); + let target_ref = FixtureRef::new(tag, branch.as_deref()); println!("Fetching the {grammar} grammar..."); @@ -24,7 +79,7 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { "--depth", "1", "--branch", - tag, + &target_ref.to_string(), &grammar_url, &grammar_dir.to_string_lossy(), ]); @@ -33,31 +88,71 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { &format!("Failed to clone the {grammar} grammar"), )?; } else { - let mut describe_command = Command::new("git"); - describe_command.current_dir(&grammar_dir).args([ - "describe", - "--tags", - "--exact-match", - "HEAD", - ]); + let (current_ref, current_ref_type) = current_ref_name(&grammar_dir)?; + if current_ref != target_ref.to_string() { + println!( + "Updating {grammar} grammar from {} {current_ref} to {} {target_ref}...", + current_ref_type.unwrap_or(""), + target_ref.ref_type(), + ); - let output = describe_command.output()?; - let current_tag = String::from_utf8_lossy(&output.stdout); - let current_tag = current_tag.trim(); - - if current_tag != tag { - println!("Updating {grammar} grammar from {current_tag} to {tag}..."); - - let mut fetch_command = Command::new("git"); - fetch_command.current_dir(&grammar_dir).args([ - "fetch", - "origin", - &format!("refs/tags/{tag}:refs/tags/{tag}"), - ]); - bail_on_err( - &fetch_command.spawn()?.wait_with_output()?, - &format!("Failed to fetch tag {tag} for {grammar} grammar"), - )?; + match target_ref { + FixtureRef::Branch(branch) => { + let mut fetch_cmd = Command::new("git"); + fetch_cmd.current_dir(&grammar_dir).args([ + "fetch", + "--update-shallow", + "origin", + &format!("+refs/heads/{branch}:refs/remotes/origin/{branch}"), + ]); + bail_on_err( + &fetch_cmd.spawn()?.wait_with_output()?, + &format!("Failed to fetch branch {branch}"), + )?; + let mut switch_cmd = Command::new("git"); + switch_cmd + .current_dir(&grammar_dir) + .args(["switch", branch]); + bail_on_err( + &switch_cmd.spawn()?.wait_with_output()?, + &format!("Failed to checkout branch {branch}"), + )?; + let mut set_upstream_cmd = Command::new("git"); + set_upstream_cmd.current_dir(&grammar_dir).args([ + "branch", + "--set-upstream-to", + &format!("origin/{branch}"), + branch, + ]); + bail_on_err( + &set_upstream_cmd.spawn()?.wait_with_output()?, + &format!("Failed to set upstream for branch {branch}"), + )?; + let mut pull_cmd = Command::new("git"); + pull_cmd + .current_dir(&grammar_dir) + .args(["pull", "origin", branch]); + bail_on_err( + &pull_cmd.spawn()?.wait_with_output()?, + &format!("Failed to pull latest from branch {branch}"), + )?; + } + FixtureRef::Tag(tag) => { + let mut fetch_command = Command::new("git"); + fetch_command.current_dir(&grammar_dir).args([ + "fetch", + "origin", + &format!("refs/tags/{tag}:refs/tags/{tag}"), + ]); + bail_on_err( + &fetch_command.spawn()?.wait_with_output()?, + &format!( + "Failed to fetch {} {target_ref} for {grammar} grammar", + target_ref.ref_type() + ), + )?; + } + } let mut reset_command = Command::new("git"); reset_command @@ -71,29 +166,23 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { let mut checkout_command = Command::new("git"); checkout_command .current_dir(&grammar_dir) - .args(["checkout", tag]); + .args(["checkout", &target_ref.to_string()]); bail_on_err( &checkout_command.spawn()?.wait_with_output()?, - &format!("Failed to checkout tag {tag} for {grammar} grammar"), + &format!( + "Failed to checkout {} {target_ref} for {grammar} grammar", + target_ref.ref_type() + ), )?; } else { - println!("{grammar} grammar is already at tag {tag}"); + println!( + "{grammar} grammar is already at {} {target_ref}", + target_ref.ref_type() + ); } } } - if args.update { - println!("Updating the fixtures lock file"); - fs::write( - &fixtures_path, - // format the JSON without extra newlines - serde_json::to_string(&fixtures)? - .replace("[[", "[\n [") - .replace("],", "],\n ") - .replace("]]", "]\n]"), - )?; - } - Ok(()) } diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 3814cf66..28ebd86a 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -36,7 +36,7 @@ enum Commands { /// Fetches emscripten. FetchEmscripten, /// Fetches the fixtures for testing tree-sitter. - FetchFixtures(FetchFixtures), + FetchFixtures, /// Generate the Rust bindings from the C library. GenerateBindings, /// Generates the fixtures for testing tree-sitter. @@ -118,13 +118,6 @@ struct Clippy { package: Option, } -#[derive(Args)] -struct FetchFixtures { - /// Update all fixtures to the latest tag - #[arg(long, short)] - update: bool, -} - #[derive(Args)] struct GenerateFixtures { /// Generates the parser to Wasm @@ -232,8 +225,8 @@ fn run() -> Result<()> { Commands::CheckWasmExports(check_options) => check_wasm_exports::run(&check_options)?, Commands::Clippy(clippy_options) => clippy::run(&clippy_options)?, Commands::FetchEmscripten => fetch::run_emscripten()?, - Commands::FetchFixtures(fetch_fixture_options) => { - fetch::run_fixtures(&fetch_fixture_options)?; + Commands::FetchFixtures => { + fetch::run_fixtures()?; } Commands::GenerateBindings => generate::run_bindings()?, Commands::GenerateFixtures(generate_fixtures_options) => { diff --git a/lib/src/array.h b/lib/src/array.h index d965c617..dfeb6c7a 100644 --- a/lib/src/array.h +++ b/lib/src/array.h @@ -52,67 +52,91 @@ extern "C" { /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is /// less than the array's current capacity, this function has no effect. -#define array_reserve(self, new_capacity) \ - _array__reserve((Array *)(self), array_elem_size(self), new_capacity) +#define array_reserve(self, new_capacity) \ + ((self)->contents = _array__reserve( \ + (void *)(self)->contents, &(self)->capacity, \ + array_elem_size(self), new_capacity) \ + ) /// Free any memory allocated for this array. Note that this does not free any /// memory allocated for the array's contents. -#define array_delete(self) _array__delete((Array *)(self)) +#define array_delete(self) _array__delete((self), (void *)(self)->contents, sizeof(*self)) /// Push a new `element` onto the end of the array. -#define array_push(self, element) \ - (_array__grow((Array *)(self), 1, array_elem_size(self)), \ - (self)->contents[(self)->size++] = (element)) +#define array_push(self, element) \ + do { \ + (self)->contents = _array__grow( \ + (void *)(self)->contents, (self)->size, &(self)->capacity, \ + 1, array_elem_size(self) \ + ); \ + (self)->contents[(self)->size++] = (element); \ + } while(0) /// Increase the array's size by `count` elements. /// New elements are zero-initialized. -#define array_grow_by(self, count) \ - do { \ - if ((count) == 0) break; \ - _array__grow((Array *)(self), count, array_elem_size(self)); \ +#define array_grow_by(self, count) \ + do { \ + if ((count) == 0) break; \ + (self)->contents = _array__grow( \ + (self)->contents, (self)->size, &(self)->capacity, \ + count, array_elem_size(self) \ + ); \ memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ - (self)->size += (count); \ + (self)->size += (count); \ } while (0) /// Append all elements from one array to the end of another. -#define array_push_all(self, other) \ +#define array_push_all(self, other) \ array_extend((self), (other)->size, (other)->contents) /// Append `count` elements to the end of the array, reading their values from the /// `contents` pointer. -#define array_extend(self, count, contents) \ - _array__splice( \ - (Array *)(self), array_elem_size(self), (self)->size, \ - 0, count, contents \ +#define array_extend(self, count, other_contents) \ + (self)->contents = _array__splice( \ + (void*)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), (self)->size, 0, count, other_contents \ ) /// Remove `old_count` elements from the array starting at the given `index`. At /// the same index, insert `new_count` new elements, reading their values from the /// `new_contents` pointer. -#define array_splice(self, _index, old_count, new_count, new_contents) \ - _array__splice( \ - (Array *)(self), array_elem_size(self), _index, \ - old_count, new_count, new_contents \ +#define array_splice(self, _index, old_count, new_count, new_contents) \ + (self)->contents = _array__splice( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), _index, old_count, new_count, new_contents \ ) /// Insert one `element` into the array at the given `index`. -#define array_insert(self, _index, element) \ - _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) +#define array_insert(self, _index, element) \ + (self)->contents = _array__splice( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + array_elem_size(self), _index, 0, 1, &(element) \ + ) /// Remove one element from the array at the given `index`. #define array_erase(self, _index) \ - _array__erase((Array *)(self), array_elem_size(self), _index) + _array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index) /// Pop the last element off the array, returning the element by value. #define array_pop(self) ((self)->contents[--(self)->size]) /// Assign the contents of one array to another, reallocating if necessary. -#define array_assign(self, other) \ - _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) +#define array_assign(self, other) \ + (self)->contents = _array__assign( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + (const void *)(other)->contents, (other)->size, array_elem_size(self) \ + ) /// Swap one array with another -#define array_swap(self, other) \ - _array__swap((Array *)(self), (Array *)(other)) +#define array_swap(self, other) \ + do { \ + struct Swap swapped_contents = _array__swap( \ + (void *)(self)->contents, &(self)->size, &(self)->capacity, \ + (void *)(other)->contents, &(other)->size, &(other)->capacity \ + ); \ + (self)->contents = swapped_contents.self_contents; \ + (other)->contents = swapped_contents.other_contents; \ + } while (0) /// Get the size of the array contents #define array_elem_size(self) (sizeof *(self)->contents) @@ -157,82 +181,112 @@ extern "C" { // Private -typedef Array(void) Array; +// Pointers to individual `Array` fields (rather than the entire `Array` itself) +// are passed to the various `_array__*` functions below to address strict aliasing +// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`. +// +// The `Array` type itself was not altered as a solution in order to avoid breakage +// with existing consumers (in particular, parsers with external scanners). /// This is not what you're looking for, see `array_delete`. -static inline void _array__delete(Array *self) { - if (self->contents) { - ts_free(self->contents); - self->contents = NULL; - self->size = 0; - self->capacity = 0; - } +static inline void _array__delete(void *self, void *contents, size_t self_size) { + if (contents) ts_free(contents); + if (self) memset(self, 0, self_size); } /// This is not what you're looking for, see `array_erase`. -static inline void _array__erase(Array *self, size_t element_size, - uint32_t index) { - ts_assert(index < self->size); - char *contents = (char *)self->contents; +static inline void _array__erase(void* self_contents, uint32_t *size, + size_t element_size, uint32_t index) { + ts_assert(index < *size); + char *contents = (char *)self_contents; memmove(contents + index * element_size, contents + (index + 1) * element_size, - (self->size - index - 1) * element_size); - self->size--; + (*size - index - 1) * element_size); + (*size)--; } /// This is not what you're looking for, see `array_reserve`. -static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { - if (new_capacity > self->capacity) { - if (self->contents) { - self->contents = ts_realloc(self->contents, new_capacity * element_size); +static inline void *_array__reserve(void *contents, uint32_t *capacity, + size_t element_size, uint32_t new_capacity) { + void *new_contents = contents; + if (new_capacity > *capacity) { + if (contents) { + new_contents = ts_realloc(contents, new_capacity * element_size); } else { - self->contents = ts_malloc(new_capacity * element_size); + new_contents = ts_malloc(new_capacity * element_size); } - self->capacity = new_capacity; + *capacity = new_capacity; } + return new_contents; } /// This is not what you're looking for, see `array_assign`. -static inline void _array__assign(Array *self, const Array *other, size_t element_size) { - _array__reserve(self, element_size, other->size); - self->size = other->size; - memcpy(self->contents, other->contents, self->size * element_size); +static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity, + const void *other_contents, uint32_t other_size, size_t element_size) { + void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size); + *self_size = other_size; + memcpy(new_contents, other_contents, *self_size * element_size); + return new_contents; } +struct Swap { + void *self_contents; + void *other_contents; +}; + /// This is not what you're looking for, see `array_swap`. -static inline void _array__swap(Array *self, Array *other) { - Array swap = *other; - *other = *self; - *self = swap; +// static inline void _array__swap(Array *self, Array *other) { +static inline struct Swap _array__swap(void *self_contents, uint32_t *self_size, uint32_t *self_capacity, + void *other_contents, uint32_t *other_size, uint32_t *other_capacity) { + void *new_self_contents = other_contents; + uint32_t new_self_size = *other_size; + uint32_t new_self_capacity = *other_capacity; + + void *new_other_contents = self_contents; + *other_size = *self_size; + *other_capacity = *self_capacity; + + *self_size = new_self_size; + *self_capacity = new_self_capacity; + + struct Swap out = { + .self_contents = new_self_contents, + .other_contents = new_other_contents, + }; + return out; } /// This is not what you're looking for, see `array_push` or `array_grow_by`. -static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { - uint32_t new_size = self->size + count; - if (new_size > self->capacity) { - uint32_t new_capacity = self->capacity * 2; +static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity, + uint32_t count, size_t element_size) { + void *new_contents = contents; + uint32_t new_size = size + count; + if (new_size > *capacity) { + uint32_t new_capacity = *capacity * 2; if (new_capacity < 8) new_capacity = 8; if (new_capacity < new_size) new_capacity = new_size; - _array__reserve(self, element_size, new_capacity); + new_contents = _array__reserve(contents, capacity, element_size, new_capacity); } + return new_contents; } /// This is not what you're looking for, see `array_splice`. -static inline void _array__splice(Array *self, size_t element_size, +static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity, + size_t element_size, uint32_t index, uint32_t old_count, uint32_t new_count, const void *elements) { - uint32_t new_size = self->size + new_count - old_count; + uint32_t new_size = *size + new_count - old_count; uint32_t old_end = index + old_count; uint32_t new_end = index + new_count; - ts_assert(old_end <= self->size); + ts_assert(old_end <= *size); - _array__reserve(self, element_size, new_size); + void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size); - char *contents = (char *)self->contents; - if (self->size > old_end) { + char *contents = (char *)new_contents; + if (*size > old_end) { memmove( contents + new_end * element_size, contents + old_end * element_size, - (self->size - old_end) * element_size + (*size - old_end) * element_size ); } if (new_count > 0) { @@ -250,7 +304,9 @@ static inline void _array__splice(Array *self, size_t element_size, ); } } - self->size += new_count - old_count; + *size += new_count - old_count; + + return new_contents; } /// A binary search routine, based on Rust's `std::slice::binary_search_by`. diff --git a/test/fixtures/fixtures.json b/test/fixtures/fixtures.json index c1e2b167..1e1596df 100644 --- a/test/fixtures/fixtures.json +++ b/test/fixtures/fixtures.json @@ -1,17 +1,17 @@ [ - ["bash","v0.25.0"], - ["c","v0.24.1"], - ["cpp","v0.23.4"], - ["embedded-template","v0.25.0"], - ["go","v0.25.0"], - ["html","v0.23.2"], - ["java","v0.23.5"], - ["javascript","v0.25.0"], - ["jsdoc","v0.23.2"], - ["json","v0.24.8"], - ["php","v0.24.2"], - ["python","v0.23.6"], - ["ruby","v0.23.1"], - ["rust","v0.24.0"], - ["typescript","v0.23.2"] -] \ No newline at end of file + ["bash","v0.25.0", null], + ["c","v0.24.1", null], + ["cpp","v0.23.4", null], + ["embedded-template","v0.25.0", null], + ["go","v0.25.0", null], + ["html","v0.23.2", null], + ["java","v0.23.5", null], + ["javascript","v0.25.0", null], + ["jsdoc","v0.23.2", null], + ["json","v0.24.8", null], + ["php","v0.24.2", "upstream_test_fixture"], + ["python","v0.23.6", null], + ["ruby","v0.23.1", null], + ["rust","v0.24.0", null], + ["typescript","v0.23.2", null] +]