v/vlib/v/util/surrounder.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.
// Note: 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()
}
}