139 lines
3.5 KiB
V
139 lines
3.5 KiB
V
module util
|
|
|
|
import strings
|
|
|
|
// Surrounder is an utility to help you manage a stack of additions, that
|
|
// should be done *both* _before_ and _after_ a given piece of generated
|
|
// code, in a synchronised way. It does so by forcing you to put the
|
|
// creation/destruction samples next to each other, so that it is easier to
|
|
// keep them in sync and spot errors.
|
|
// NB: Surrounder writes the creation samples (`befores`) in the _same_ order
|
|
// they were added, and the destruction samples (`afters`) in _reverse_ order.
|
|
//
|
|
// Usage:
|
|
// ```v
|
|
// mut sr := new_surrounder(2) // just a rough initial guess; it can grow
|
|
// sr.add('string tmp1 = ...;', 'string_free(&tmp1);')
|
|
// sr.add('string tmp2 = ...;', 'string_free(&tmp2);')
|
|
// ..
|
|
// sr.builder_write_befores(mut some_string_builder)
|
|
// some_string_builder.writeln('MIDDLE_that_uses_tmp1_and_tmp2')
|
|
// sr.builder_write_afters(mut some_string_builder)
|
|
// ```
|
|
// ... will produce this in `some_string_builder`:
|
|
// ```
|
|
// string tmp1 = ...;
|
|
// string tmp2 = ...;
|
|
// MIDDLE_that_uses_tmp1_and_tmp2
|
|
// string_free(&tmp2);
|
|
// string_free(&tmp1);
|
|
// ```
|
|
|
|
[noinit]
|
|
pub struct Surrounder {
|
|
mut:
|
|
befores []string
|
|
afters []string
|
|
}
|
|
|
|
// new_surrounder creates a new Surrounder instance.
|
|
// The expected_length is a hint for the initial capacity for the
|
|
// befores/afters stacks.
|
|
pub fn new_surrounder(expected_length int) Surrounder {
|
|
return Surrounder{
|
|
befores: []string{cap: expected_length}
|
|
afters: []string{cap: expected_length}
|
|
}
|
|
}
|
|
|
|
// add appends a `before`/`after` pair to the surrounder
|
|
// When you call .after() or .builder_write_afters(),
|
|
// all `before` parts will be in order, while all `after`
|
|
// parts, will be in reverse order.
|
|
pub fn (mut s Surrounder) add(before string, after string) {
|
|
s.befores << before
|
|
s.afters << after
|
|
}
|
|
|
|
// before returns all the `before` parts that were accumulated so far
|
|
[manualfree]
|
|
pub fn (s &Surrounder) before() string {
|
|
len := s.befores.len
|
|
if len > 0 {
|
|
mut res := strings.new_builder(len * 100)
|
|
defer {
|
|
unsafe { res.free() }
|
|
}
|
|
for i := 0; i < len; i++ {
|
|
x := s.befores[i]
|
|
if x.len > 0 {
|
|
res.writeln(x)
|
|
}
|
|
}
|
|
ret := res.str()
|
|
return ret
|
|
}
|
|
return ''
|
|
}
|
|
|
|
// after returns all the `after` parts that were accumulated so far,
|
|
// in reverse order of their addition.
|
|
[manualfree]
|
|
pub fn (s &Surrounder) after() string {
|
|
len := s.afters.len
|
|
if len > 0 {
|
|
mut res := strings.new_builder(len * 100)
|
|
defer {
|
|
unsafe { res.free() }
|
|
}
|
|
for i := len - 1; i >= 0; i-- {
|
|
x := s.afters[i]
|
|
if x.len > 0 {
|
|
res.writeln(x)
|
|
}
|
|
}
|
|
ret := res.str()
|
|
return ret
|
|
}
|
|
return ''
|
|
}
|
|
|
|
// builder_write_befores writeln-es all the `before` parts into the given
|
|
// string builder `sb`.
|
|
pub fn (s &Surrounder) builder_write_befores(mut sb strings.Builder) {
|
|
len := s.befores.len
|
|
if len > 0 {
|
|
for i := 0; i < len; i++ {
|
|
x := s.befores[i]
|
|
if x.len > 0 {
|
|
sb.writeln(x)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// builder_write_afters writeln-es all the `after` parts into the given
|
|
// string builder `sb`. They will be written there in reverse order, compared
|
|
// to how/when they were added.
|
|
pub fn (s &Surrounder) builder_write_afters(mut sb strings.Builder) {
|
|
len := s.afters.len
|
|
if len > 0 {
|
|
for i := len - 1; i >= 0; i-- {
|
|
x := s.afters[i]
|
|
if x.len > 0 {
|
|
sb.writeln(x)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// free frees the private resources associated with the surrounder instance
|
|
// Called automatically by `-autofree`, or in `[manualfree]` tagged functions.
|
|
[unsafe]
|
|
pub fn (mut s Surrounder) free() {
|
|
unsafe {
|
|
s.befores.free()
|
|
s.afters.free()
|
|
}
|
|
}
|