Open JohelEGP opened 5 years ago
Just for curiosity - what it should do, or better say what it good for? Usage example would be nice.
I use it to assert that some input has balanced pairs of parentheses: https://github.github.com/gfm/#example-505.
I would never guessed that "balanced pairs" means "balanced parentheses"...
"balanced scopes" ?
Perhaps "brackets" would be clearer.
What if that not brackets, but some begin/end markers? But I agree, that brackets clearer than pairs...
has_balanced_markers
sounds good to me. But not too much more than has_balanced_brackets
.
BTW, if it tests that ALL markers are balanced, it probably should start with "is", not "has" . Like "is_balanced". Or on the contrary - "has_unbalanced_brackets".
Because "has_balanced_brackets" imply that at least some brackets are balanced.
It's true that has might imply that there are some unbalanced markers. But does is really implies that all the markers are balanced? And yes, it's supposed to test that all markers are balanced.
Thank you for helping me improve this.
The iterator in the returned result type is last
or the first unbalanced closing_marker
. If there was a unbalanced_marker(r, opening_marker, closing_marker)
that only returned the iterator, what would you call the algorithm to return unbalanced_marker(r, opening_marker, closing_marker) == end(r)
?
contains_unbalanced_marker
contains_unbalanced_markers
Or better - has_unbalanced_scope
Those names have the same problem as the prefix has_
in that they imply that not all markers are balanced.
!has_unbalanced_scope = all_scopes_are_balanced if there is no a single unbalanced scope - then all scopes are balanced.
find_open_block(rng, block_start, block_end) -> option<iterator_range(block_begin, block_end)>
That's the best. Thank you. I'll let others chime in on whether to prefer marker or scope, assuming that the project owner is OK with me pushing my algorithms here rather than making my personal algorithm's library.
find_open_block(rng, block_start, block_end) -> option<iterator_range(block_begin, block_end)>
Are you proposing a generalization?
Are you proposing a generalization?
Hmm... that probably would be separate algorithm.
template<
class Rng,
class Start, class End,
class StartProj = ident, class EndProj = ident,
class StartComparator = default_equal, class EndComparator = default_equal>
auto /* sequence of not closed (unbalanced) blocks */
find_open_blocks(
Rng&& range,
const Start& block_start, const End& block_end,
StartProj start_proj = StartProj{}, EndProj end_proj = EndProj{},
StartComparator start_comp = StartComparator{}, EndComparator end_comp = EndComparator{}
)
Usage:
std::string str = "[ Hello [World [[!!!] ]"
auto open_blocks = find_open_blocks(str, '[', ']');
// Output:
// "[Hello ... ]"
// "[World ... ]"
That would require ForwardRange and temporary std::stack<Iterator>
to track curently opened blocks.
Which in turns ....
// return range of custom ranges:
// struct Block{ iterator begin(); iterator end(); bool is_open(); }
auto blocks = find_blocks(str, '[', ']');
bool all_blocks_closed = contains(find_blocks(str, '[', ']'), true, &Block::is_open);
Which probably is not what you want.... Because this begin to look like a parser...
Has unbalanced marker
Interface
Constraints:
For the first form:
ranges::InputIterator<I>
istrue
,ranges::Sentinel<S, I>
istrue
, andranges::IndirectRelation<ranges::equal_to, ranges::projected<I, Proj>, const T*>
istrue
.For the second form:
ranges::InputRange<R>
istrue
, andranges::IndirectRelation<ranges::equal_to, ranges::projected<ranges::iterator_t<R>, Proj>, const T*>
istrue
.Expects:
opening_marker
is not equal toclosing_marker
.Let
opening
andclosing
be the number of projected elements that equalopening_marker
andclosing_marker
, respectively, in [first
,i + 1
) ifi
is specified and [first
,last
) otherwise.Returns:
{true, i}
for the first iteratori
in the range [first
,last
) for whichopening < closing
. Otherwise,{opening != closing, last}
.Complexity: At most
last - first
applications of the projection and no more than twice as many comparisons.Constraints:
ranges::ConvertibleTo<const I&, I2>
istrue
.Returns:
{value, in}
.Constraints:
ranges::ConvertibleTo<I, I2>
istrue
.Returns:
{value, std::move(in)}
.Possible implementation