#ifndef PERL_INVLIST_INLINE_H_
#define PERL_INVLIST_INLINE_H_
#if defined(PERL_IN_UTF8_C) \
|| defined(PERL_IN_REGCOMP_ANY) \
|| defined(PERL_IN_REGEXEC_C) \
|| defined(PERL_IN_TOKE_C) \
|| defined(PERL_IN_PP_C) \
|| defined(PERL_IN_OP_C) \
|| defined(PERL_IN_DOOP_C)
#define ELEMENT_RANGE_MATCHES_INVLIST(i) (! ((i) & 1))
#define PREV_RANGE_MATCHES_INVLIST(i) (! ELEMENT_RANGE_MATCHES_INVLIST(i))
#define TO_INTERNAL_SIZE(x) ((x) * sizeof(UV))
#define FROM_INTERNAL_SIZE(x) ((x)/ sizeof(UV))
PERL_STATIC_INLINE
bool
S_is_invlist(
const
SV*
const
invlist)
{
return
invlist != NULL && SvTYPE(invlist) == SVt_INVLIST;
}
PERL_STATIC_INLINE
bool
*
S_get_invlist_offset_addr(SV* invlist)
{
PERL_ARGS_ASSERT_GET_INVLIST_OFFSET_ADDR;
assert
(is_invlist(invlist));
return
&(((XINVLIST*) SvANY(invlist))->is_offset);
}
PERL_STATIC_INLINE UV
S__invlist_len(SV*
const
invlist)
{
PERL_ARGS_ASSERT__INVLIST_LEN;
assert
(is_invlist(invlist));
return
(SvCUR(invlist) == 0)
? 0
: FROM_INTERNAL_SIZE(SvCUR(invlist)) - *get_invlist_offset_addr(invlist);
}
PERL_STATIC_INLINE
bool
S__invlist_contains_cp(SV*
const
invlist,
const
UV cp)
{
IV index = _invlist_search(invlist, cp);
PERL_ARGS_ASSERT__INVLIST_CONTAINS_CP;
return
index >= 0 && ELEMENT_RANGE_MATCHES_INVLIST(index);
}
PERL_STATIC_INLINE UV*
S_invlist_array(SV*
const
invlist)
{
PERL_ARGS_ASSERT_INVLIST_ARRAY;
assert
(_invlist_len(invlist));
assert
(0 == *(SvPVX(invlist)));
return
((UV *) SvPVX(invlist) + *get_invlist_offset_addr(invlist));
}
#endif
#if defined(PERL_IN_REGCOMP_ANY) || defined(PERL_IN_OP_C) || defined(PERL_IN_DOOP_C)
PERL_STATIC_INLINE
void
S_invlist_extend(pTHX_ SV*
const
invlist,
const
UV new_max)
{
PERL_ARGS_ASSERT_INVLIST_EXTEND;
assert
(SvTYPE(invlist) == SVt_INVLIST);
SvGROW((SV *)invlist, TO_INTERNAL_SIZE(new_max + 1));
}
PERL_STATIC_INLINE
void
S_invlist_set_len(pTHX_ SV*
const
invlist,
const
UV len,
const
bool
offset)
{
PERL_UNUSED_CONTEXT;
PERL_ARGS_ASSERT_INVLIST_SET_LEN;
assert
(SvTYPE(invlist) == SVt_INVLIST);
SvCUR_set(invlist,
(len == 0)
? 0
: TO_INTERNAL_SIZE(len + offset));
assert
(SvLEN(invlist) == 0 || SvCUR(invlist) <= SvLEN(invlist));
}
PERL_STATIC_INLINE SV*
S_add_cp_to_invlist(pTHX_ SV* invlist,
const
UV cp) {
return
_add_range_to_invlist(invlist, cp, cp);
}
PERL_STATIC_INLINE UV
S_invlist_highest(SV*
const
invlist)
{
UV len = _invlist_len(invlist);
UV *array;
PERL_ARGS_ASSERT_INVLIST_HIGHEST;
if
(len == 0) {
return
0;
}
array = invlist_array(invlist);
return
(ELEMENT_RANGE_MATCHES_INVLIST(len - 1))
? UV_MAX
: array[len - 1] - 1;
}
# if defined(PERL_IN_REGCOMP_ANY)
PERL_STATIC_INLINE UV
S_invlist_highest_range_start(SV*
const
invlist)
{
UV len = _invlist_len(invlist);
UV *array;
PERL_ARGS_ASSERT_INVLIST_HIGHEST_RANGE_START;
if
(len == 0) {
return
0;
}
array = invlist_array(invlist);
return
(ELEMENT_RANGE_MATCHES_INVLIST(len - 1))
? array[len - 1]
: len == 1
? 0
: array[len - 2];
}
# endif
#endif
#if defined(PERL_IN_REGCOMP_ANY) || defined(PERL_IN_OP_C)
PERL_STATIC_INLINE STRLEN*
S_get_invlist_iter_addr(SV* invlist)
{
PERL_ARGS_ASSERT_GET_INVLIST_ITER_ADDR;
assert
(is_invlist(invlist));
return
&(((XINVLIST*) SvANY(invlist))->iterator);
}
PERL_STATIC_INLINE
void
S_invlist_iterinit(SV* invlist)
{
PERL_ARGS_ASSERT_INVLIST_ITERINIT;
*get_invlist_iter_addr(invlist) = 0;
}
PERL_STATIC_INLINE
void
S_invlist_iterfinish(SV* invlist)
{
PERL_ARGS_ASSERT_INVLIST_ITERFINISH;
*get_invlist_iter_addr(invlist) = (STRLEN) UV_MAX;
}
STATIC
bool
S_invlist_iternext(SV* invlist, UV* start, UV* end)
{
STRLEN* pos = get_invlist_iter_addr(invlist);
UV len = _invlist_len(invlist);
UV *array;
PERL_ARGS_ASSERT_INVLIST_ITERNEXT;
if
(*pos >= len) {
*pos = (STRLEN) UV_MAX;
return
FALSE;
}
array = invlist_array(invlist);
*start = array[(*pos)++];
if
(*pos >= len) {
*end = UV_MAX;
}
else
{
*end = array[(*pos)++] - 1;
}
return
TRUE;
}
#endif
#ifndef PERL_IN_REGCOMP_ANY
# undef TO_INTERNAL_SIZE
# undef FROM_INTERNAL_SIZE
#endif
#ifdef PERL_IN_REGCOMP_ANY
PERL_STATIC_INLINE
bool
S_invlist_is_iterating(
const
SV*
const
invlist)
{
PERL_ARGS_ASSERT_INVLIST_IS_ITERATING;
return
*(get_invlist_iter_addr((SV*)invlist)) < (STRLEN) UV_MAX;
}
PERL_STATIC_INLINE
SV *
S_invlist_contents(pTHX_ SV*
const
invlist,
const
bool
traditional_style)
{
UV start, end;
SV* output;
const
char
intra_range_delimiter = (traditional_style ?
'\t'
:
'-'
);
const
char
inter_range_delimiter = (traditional_style ?
'\n'
:
' '
);
if
(traditional_style) {
output = newSVpvs(
"\n"
);
}
else
{
output = newSVpvs(
""
);
}
PERL_ARGS_ASSERT_INVLIST_CONTENTS;
assert
(! invlist_is_iterating(invlist));
invlist_iterinit(invlist);
while
(invlist_iternext(invlist, &start, &end)) {
if
(end == UV_MAX) {
Perl_sv_catpvf(aTHX_ output,
"%04"
UVXf
"%cINFTY%c"
,
start, intra_range_delimiter,
inter_range_delimiter);
}
else
if
(end != start) {
Perl_sv_catpvf(aTHX_ output,
"%04"
UVXf
"%c%04"
UVXf
"%c"
,
start,
intra_range_delimiter,
end, inter_range_delimiter);
}
else
{
Perl_sv_catpvf(aTHX_ output,
"%04"
UVXf
"%c"
,
start, inter_range_delimiter);
}
}
if
(SvCUR(output) && ! traditional_style) {
SvCUR_set(output, SvCUR(output) - 1);
}
return
output;
}
PERL_STATIC_INLINE
UV
S_invlist_lowest(SV*
const
invlist)
{
UV len = _invlist_len(invlist);
UV *array;
PERL_ARGS_ASSERT_INVLIST_LOWEST;
if
(len == 0) {
return
0;
}
array = invlist_array(invlist);
return
array[0];
}
#endif
#endif /* PERL_INVLIST_INLINE_H_ */