aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2022-11-17 18:09:37 -0500
committerStefan Monnier2022-11-17 18:09:37 -0500
commit091e0f04ffe494ee4cddb67670f0c495a7c9b691 (patch)
tree3e93d67eed88aeea94cc78951e987fedffd7d8ea
parentfb7f1864da4aa4c09756cfe47db6c56b4e87bd14 (diff)
downloademacs-scratch/noverlay.tar.gz
emacs-scratch/noverlay.zip
itree.c: Get rid of the old iterator codescratch/noverlay
Only use the new iterator which relies on a fixed size (and small) state in the iterator. This makes non-local exits safe within ITREE_FOREACH loops. * src/itree.c (make_nav, nav_nodeptr, nav_flag, itree_stack_clear) (itree_stack_push_flagged): Delete functions. (nodeptr_and_flag): Delete type. (struct itree_stack): Make the array hold plain pointers instead. (itree_stack_push): Inline the former code of `itree_stack_push_flagged`. (itree_stack_pop): Change return type. (itree_contains): Don't call `ITREE_FOREACH_ABORT` any more. (itree_insert_gap): Simplify access to the stack of nodes. (itree_delete_gap, itree_insert_gap): Adjust code to new return type of `itree_stack_pop`. (itree_iterator_finish): Delete function. (itree_iterator_start): Don't setup the `stack` field any more. (itree_iterator_next): Delete function. (itree_iter_next): Rename to `itree_iterator_next` and make it non-static. (itree_iterator_narrow): Don't check the `running` flag any more. * src/itree.h (itree_iterator_finish): Remove declaration. (struct itree_iterator): Remove the `stack` and `running` fields. (ITREE_FOREACH_ABORT): Delete macro. (ITREE_FOREACH): Don't call `itree_iterator_finish` any more. * src/xdisp.c (strings_with_newlines): * src/buffer.c (overlays_in, next_overlay_change, overlay_touches_p): Don't call `ITREE_FOREACH_ABORT` any more.
-rw-r--r--src/buffer.c12
-rw-r--r--src/itree.c199
-rw-r--r--src/itree.h16
-rw-r--r--src/xdisp.c10
4 files changed, 23 insertions, 214 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 9be2c4a970e..4da5b451d0f 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2985,17 +2985,13 @@ overlays_in (ptrdiff_t beg, ptrdiff_t end, bool extend,
2985 if (node->begin > end) 2985 if (node->begin > end)
2986 { 2986 {
2987 next = min (next, node->begin); 2987 next = min (next, node->begin);
2988 ITREE_FOREACH_ABORT ();
2989 break; 2988 break;
2990 } 2989 }
2991 else if (node->begin == end) 2990 else if (node->begin == end)
2992 { 2991 {
2993 next = node->begin; 2992 next = node->begin;
2994 if ((! empty || end < ZV) && beg < end) 2993 if ((! empty || end < ZV) && beg < end)
2995 { 2994 break;
2996 ITREE_FOREACH_ABORT ();
2997 break;
2998 }
2999 if (empty && node->begin != node->end) 2995 if (empty && node->begin != node->end)
3000 continue; 2996 continue;
3001 } 2997 }
@@ -3050,7 +3046,6 @@ next_overlay_change (ptrdiff_t pos)
3050 of pos, because the search is limited to [pos,next) . */ 3046 of pos, because the search is limited to [pos,next) . */
3051 eassert (node->begin < next); 3047 eassert (node->begin < next);
3052 next = node->begin; 3048 next = node->begin;
3053 ITREE_FOREACH_ABORT ();
3054 break; 3049 break;
3055 } 3050 }
3056 else if (node->begin < node->end && node->end < next) 3051 else if (node->begin < node->end && node->end < next)
@@ -3155,10 +3150,7 @@ overlay_touches_p (ptrdiff_t pos)
3155 pos. */ 3150 pos. */
3156 ITREE_FOREACH (node, current_buffer->overlays, pos - 1, pos + 1, DESCENDING) 3151 ITREE_FOREACH (node, current_buffer->overlays, pos - 1, pos + 1, DESCENDING)
3157 if (node->begin == pos || node->end == pos) 3152 if (node->begin == pos || node->end == pos)
3158 { 3153 return true;
3159 ITREE_FOREACH_ABORT ();
3160 return true;
3161 }
3162 return false; 3154 return false;
3163} 3155}
3164 3156
diff --git a/src/itree.c b/src/itree.c
index 9e60071980d..e4d5fb304b7 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -131,33 +131,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
131 * | Stack 131 * | Stack
132 * +=======================================================================+ */ 132 * +=======================================================================+ */
133 133
134typedef uintptr_t nodeptr_and_flag;
135
136static inline nodeptr_and_flag
137make_nav (struct itree_node *ptr, bool flag)
138{
139 uintptr_t v = (uintptr_t) ptr;
140 /* We assume alignment imposes the LSB is clear for us to use it. */
141 eassert (!(v & 1));
142 return v | !!flag;
143}
144
145static inline struct itree_node *
146nav_nodeptr (nodeptr_and_flag nav)
147{
148 return (struct itree_node *) (nav & (~(uintptr_t)1));
149}
150
151static inline bool
152nav_flag (nodeptr_and_flag nav)
153{
154 return (bool) (nav & 1);
155}
156
157/* Simple dynamic array. */ 134/* Simple dynamic array. */
158struct itree_stack 135struct itree_stack
159{ 136{
160 nodeptr_and_flag *nodes; 137 struct itree_node **nodes;
161 size_t size; 138 size_t size;
162 size_t length; 139 size_t length;
163}; 140};
@@ -184,12 +161,6 @@ itree_stack_destroy (struct itree_stack *stack)
184 xfree (stack); 161 xfree (stack);
185} 162}
186 163
187static void
188itree_stack_clear (struct itree_stack *stack)
189{
190 stack->length = 0;
191}
192
193static inline void 164static inline void
194itree_stack_ensure_space (struct itree_stack *stack, uintmax_t nelements) 165itree_stack_ensure_space (struct itree_stack *stack, uintmax_t nelements)
195{ 166{
@@ -204,34 +175,20 @@ itree_stack_ensure_space (struct itree_stack *stack, uintmax_t nelements)
204/* Push NODE on the STACK, while settings its visited flag to FLAG. */ 175/* Push NODE on the STACK, while settings its visited flag to FLAG. */
205 176
206static inline void 177static inline void
207itree_stack_push_flagged (struct itree_stack *stack, 178itree_stack_push (struct itree_stack *stack, struct itree_node *node)
208 struct itree_node *node, bool flag)
209{ 179{
210 eassert (node); 180 eassert (node);
211
212 /* FIXME: While the stack used in the iterator is bounded by the tree
213 depth and could be easily pre-allocated to a large enough size to avoid
214 this "ensure" check, `itree_stack_push` is also used elsewhere to
215 simply collect some subset of the overlays, where it's only bounded by
216 the total number of overlays in the buffer (which can be large and thus
217 preferably not pre-allocated needlessly). */
218 itree_stack_ensure_space (stack, stack->length + 1); 181 itree_stack_ensure_space (stack, stack->length + 1);
219 182
220 stack->nodes[stack->length] = make_nav (node, flag); 183 stack->nodes[stack->length] = node;
221 stack->length++; 184 stack->length++;
222} 185}
223 186
224static inline void 187static inline struct itree_node *
225itree_stack_push (struct itree_stack *stack, struct itree_node *node)
226{
227 itree_stack_push_flagged (stack, node, false);
228}
229
230static inline nodeptr_and_flag
231itree_stack_pop (struct itree_stack *stack) 188itree_stack_pop (struct itree_stack *stack)
232{ 189{
233 if (stack->length == 0) 190 if (stack->length == 0)
234 return make_nav (NULL, false); 191 return NULL;
235 return stack->nodes[--stack->length]; 192 return stack->nodes[--stack->length];
236} 193}
237 194
@@ -815,10 +772,7 @@ itree_contains (struct itree_tree *tree, struct itree_node *node)
815 struct itree_node *other; 772 struct itree_node *other;
816 ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING) 773 ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING)
817 if (other == node) 774 if (other == node)
818 { 775 return true;
819 ITREE_FOREACH_ABORT ();
820 return true;
821 }
822 776
823 return false; 777 return false;
824} 778}
@@ -1122,7 +1076,7 @@ itree_insert_gap (struct itree_tree *tree,
1122 } 1076 }
1123 } 1077 }
1124 for (size_t i = 0; i < saved->length; ++i) 1078 for (size_t i = 0; i < saved->length; ++i)
1125 itree_remove (tree, nav_nodeptr (saved->nodes[i])); 1079 itree_remove (tree, saved->nodes[i]);
1126 1080
1127 /* We can't use an iterator here, because we can't effectively 1081 /* We can't use an iterator here, because we can't effectively
1128 narrow AND shift some subtree at the same time. */ 1082 narrow AND shift some subtree at the same time. */
@@ -1131,9 +1085,7 @@ itree_insert_gap (struct itree_tree *tree,
1131 const int size = itree_max_height (tree) + 1; 1085 const int size = itree_max_height (tree) + 1;
1132 struct itree_stack *stack = itree_stack_create (size); 1086 struct itree_stack *stack = itree_stack_create (size);
1133 itree_stack_push (stack, tree->root); 1087 itree_stack_push (stack, tree->root);
1134 nodeptr_and_flag nav; 1088 while ((node = itree_stack_pop (stack)))
1135 while ((nav = itree_stack_pop (stack),
1136 node = nav_nodeptr (nav)))
1137 { 1089 {
1138 /* Process in pre-order. */ 1090 /* Process in pre-order. */
1139 itree_inherit_offset (tree->otick, node); 1091 itree_inherit_offset (tree->otick, node);
@@ -1170,9 +1122,7 @@ itree_insert_gap (struct itree_tree *tree,
1170 1122
1171 /* Reinsert nodes starting at POS having front-advance. */ 1123 /* Reinsert nodes starting at POS having front-advance. */
1172 uintmax_t notick = tree->otick; 1124 uintmax_t notick = tree->otick;
1173 nodeptr_and_flag nav; 1125 while ((node = itree_stack_pop (saved)))
1174 while ((nav = itree_stack_pop (saved),
1175 node = nav_nodeptr (nav)))
1176 { 1126 {
1177 eassert (node->otick == ootick); 1127 eassert (node->otick == ootick);
1178 eassert (node->begin == pos); 1128 eassert (node->begin == pos);
@@ -1205,10 +1155,8 @@ itree_delete_gap (struct itree_tree *tree,
1205 struct itree_node *node; 1155 struct itree_node *node;
1206 1156
1207 itree_stack_push (stack, tree->root); 1157 itree_stack_push (stack, tree->root);
1208 nodeptr_and_flag nav; 1158 while ((node = itree_stack_pop (stack)))
1209 while ((nav = itree_stack_pop (stack)))
1210 { 1159 {
1211 node = nav_nodeptr (nav);
1212 itree_inherit_offset (tree->otick, node); 1160 itree_inherit_offset (tree->otick, node);
1213 if (pos > node->limit) 1161 if (pos > node->limit)
1214 continue; 1162 continue;
@@ -1244,16 +1192,6 @@ itree_delete_gap (struct itree_tree *tree,
1244 * | Iterator 1192 * | Iterator
1245 * +=======================================================================+ */ 1193 * +=======================================================================+ */
1246 1194
1247/* Stop using the iterator. */
1248
1249void
1250itree_iterator_finish (struct itree_iterator *iter)
1251{
1252 eassert (iter && iter->running);
1253 itree_stack_destroy (iter->stack);
1254 iter->running = false;
1255}
1256
1257/* Return true, if NODE's interval intersects with [BEGIN, END). 1195/* Return true, if NODE's interval intersects with [BEGIN, END).
1258 Note: We always include empty nodes at BEGIN (and not at END), 1196 Note: We always include empty nodes at BEGIN (and not at END),
1259 but if BEGIN==END, then we don't include non-empty nodes starting 1197 but if BEGIN==END, then we don't include non-empty nodes starting
@@ -1436,7 +1374,7 @@ itree_iterator_first_node (struct itree_tree *tree,
1436} 1374}
1437 1375
1438/* Start a iterator enumerating all intervals in [BEGIN,END) in the 1376/* Start a iterator enumerating all intervals in [BEGIN,END) in the
1439 given ORDER. Only one iterator per tree can be running at any time. */ 1377 given ORDER. */
1440 1378
1441struct itree_iterator * 1379struct itree_iterator *
1442itree_iterator_start (struct itree_iterator *iter, 1380itree_iterator_start (struct itree_iterator *iter,
@@ -1444,133 +1382,28 @@ itree_iterator_start (struct itree_iterator *iter,
1444 ptrdiff_t begin, ptrdiff_t end, enum itree_order order) 1382 ptrdiff_t begin, ptrdiff_t end, enum itree_order order)
1445{ 1383{
1446 eassert (iter); 1384 eassert (iter);
1447 /* eassert (!iter->running); */
1448 /* 19 here just avoids starting with a silly-small stack.
1449 FIXME: Since this stack only needs to be about 2*max_depth
1450 in the worst case, we could completely pre-allocate it to something
1451 like word-bit-size * 2 and then never worry about growing it. */
1452 const int size = (tree ? itree_max_height (tree) : 19) + 1;
1453 iter->stack = itree_stack_create (size);
1454 uintmax_t otick= tree->otick;
1455 iter->begin = begin; 1385 iter->begin = begin;
1456 iter->end = end; 1386 iter->end = end;
1457 iter->otick = otick; 1387 iter->otick = tree->otick;
1458 iter->order = order; 1388 iter->order = order;
1459 itree_stack_clear (iter->stack);
1460 if (begin <= end && tree->root != NULL)
1461 itree_stack_push_flagged (iter->stack, tree->root, false);
1462 iter->running = true;
1463 /* itree_stack_ensure_space (iter->stack,
1464 2 * itree_max_height (tree)); */
1465 iter->node = itree_iterator_first_node (tree, iter); 1389 iter->node = itree_iterator_first_node (tree, iter);
1466 return iter; 1390 return iter;
1467} 1391}
1468 1392
1469static struct itree_node * 1393struct itree_node *
1470itree_iter_next (struct itree_iterator *iter) 1394itree_iterator_next (struct itree_iterator *iter)
1471{ 1395{
1472 struct itree_node *node = iter->node; 1396 struct itree_node *node = iter->node;
1473 while (node 1397 while (node
1474 && !itree_node_intersects (node, iter->begin, iter->end)) 1398 && !itree_node_intersects (node, iter->begin, iter->end))
1475 { 1399 {
1476 node = itree_iter_next_in_subtree (node, iter); 1400 node = itree_iter_next_in_subtree (node, iter);
1401 eassert (itree_limit_is_stable (node));
1477 } 1402 }
1478 iter->node = node ? itree_iter_next_in_subtree (node, iter) : NULL; 1403 iter->node = node ? itree_iter_next_in_subtree (node, iter) : NULL;
1479 return node; 1404 return node;
1480} 1405}
1481 1406
1482/* Return the next node of the iterator in the order given when it was
1483 started; or NULL if there are no more nodes. */
1484
1485struct itree_node *
1486itree_iterator_next (struct itree_iterator *g)
1487{
1488 eassert (g && g->running);
1489
1490 struct itree_node *const null = NULL;
1491 struct itree_node *node;
1492
1493 /* The `visited` flag stored in each node is used here (and only here):
1494 We keep a "workstack" of nodes we need to consider. This stack
1495 consist of nodes of two types: nodes that we have decided
1496 should be returned by the iterator, and nodes which we may
1497 need to consider (including checking their children).
1498 We start an iteration with a stack containing just the root
1499 node marked as "not visited" which means that it (and its children)
1500 needs to be considered but we haven't yet decided whether it's included
1501 in the iterator's output. */
1502
1503 do
1504 {
1505 nodeptr_and_flag nav;
1506 bool visited;
1507 while ((nav = itree_stack_pop (g->stack),
1508 node = nav_nodeptr (nav),
1509 visited = nav_flag (nav),
1510 node && !visited))
1511 {
1512 struct itree_node *const left = node->left;
1513 struct itree_node *const right = node->right;
1514
1515 itree_inherit_offset (g->otick, node);
1516 eassert (itree_limit_is_stable (node));
1517 switch (g->order)
1518 {
1519 case ITREE_ASCENDING:
1520 if (right != null && node->begin <= g->end)
1521 itree_stack_push_flagged (g->stack, right, false);
1522 if (itree_node_intersects (node, g->begin, g->end))
1523 itree_stack_push_flagged (g->stack, node, true);
1524 /* Node's children may still be off-set and we need to add it. */
1525 if (left != null && g->begin <= left->limit + left->offset)
1526 itree_stack_push_flagged (g->stack, left, false);
1527 break;
1528 case ITREE_DESCENDING:
1529 if (left != null && g->begin <= left->limit + left->offset)
1530 itree_stack_push_flagged (g->stack, left, false);
1531 if (itree_node_intersects (node, g->begin, g->end))
1532 itree_stack_push_flagged (g->stack, node, true);
1533 if (right != null && node->begin <= g->end)
1534 itree_stack_push_flagged (g->stack, right, false);
1535 break;
1536 case ITREE_PRE_ORDER:
1537 if (right != null && node->begin <= g->end)
1538 itree_stack_push_flagged (g->stack, right, false);
1539 if (left != null && g->begin <= left->limit + left->offset)
1540 itree_stack_push_flagged (g->stack, left, false);
1541 if (itree_node_intersects (node, g->begin, g->end))
1542 itree_stack_push_flagged (g->stack, node, true);
1543 break;
1544 case ITREE_POST_ORDER:
1545 if (itree_node_intersects (node, g->begin, g->end))
1546 itree_stack_push_flagged (g->stack, node, true);
1547 if (right != null && node->begin <= g->end)
1548 itree_stack_push_flagged (g->stack, right, false);
1549 if (left != null && g->begin <= left->limit + left->offset)
1550 itree_stack_push_flagged (g->stack, left, false);
1551 break;
1552 }
1553 }
1554 /* Node may have been invalidated by itree_iterator_narrow
1555 after it was pushed: Check if it still intersects. */
1556 } while (node && ! itree_node_intersects (node, g->begin, g->end));
1557
1558 struct itree_node *old_node = g->node;
1559 struct itree_node *other_node = itree_iter_next (g);
1560 if (other_node != node)
1561 {
1562 fprintf (stderr, "WOW!! %ld..%ld vs %ld..%ld\n",
1563 other_node ? other_node->begin : -1,
1564 other_node ? other_node->end : -1,
1565 node ? node->begin : -1,
1566 node ? node->end : -1);
1567 fprintf (stderr, "ON=%lx N=%lx OlN=%lx\n", other_node, node,
1568 old_node);
1569 emacs_abort ();
1570 }
1571 return node;
1572}
1573
1574/* Limit G to the new interval [BEGIN, END), which must be a subset of 1407/* Limit G to the new interval [BEGIN, END), which must be a subset of
1575 the current one. I.E. it can't grow on either side. */ 1408 the current one. I.E. it can't grow on either side. */
1576 1409
@@ -1578,7 +1411,7 @@ void
1578itree_iterator_narrow (struct itree_iterator *g, 1411itree_iterator_narrow (struct itree_iterator *g,
1579 ptrdiff_t begin, ptrdiff_t end) 1412 ptrdiff_t begin, ptrdiff_t end)
1580{ 1413{
1581 eassert (g && g->running); 1414 eassert (g);
1582 eassert (begin >= g->begin); 1415 eassert (begin >= g->begin);
1583 eassert (end <= g->end); 1416 eassert (end <= g->end);
1584 g->begin = max (begin, g->begin); 1417 g->begin = max (begin, g->begin);
diff --git a/src/itree.h b/src/itree.h
index 37cd423d34a..291fa53fd30 100644
--- a/src/itree.h
+++ b/src/itree.h
@@ -132,24 +132,21 @@ extern struct itree_iterator *itree_iterator_start (struct itree_iterator *,
132 enum itree_order); 132 enum itree_order);
133extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t, 133extern void itree_iterator_narrow (struct itree_iterator *, ptrdiff_t,
134 ptrdiff_t); 134 ptrdiff_t);
135extern void itree_iterator_finish (struct itree_iterator *);
136extern struct itree_node *itree_iterator_next (struct itree_iterator *); 135extern struct itree_node *itree_iterator_next (struct itree_iterator *);
137 136
138/* State used when iterating interval. */ 137/* State used when iterating interval. */
139struct itree_iterator 138struct itree_iterator
140 { 139 {
141 struct itree_node *node; /* FIXME: It should be either `node` or `stack`. */ 140 struct itree_node *node;
142 struct itree_stack *stack;
143 ptrdiff_t begin; 141 ptrdiff_t begin;
144 ptrdiff_t end; 142 ptrdiff_t end;
145 uintmax_t otick; /* A copy of the tree's `otick`. */ 143 uintmax_t otick; /* A copy of the tree's `otick`. */
146 enum itree_order order; 144 enum itree_order order;
147 bool running;
148 }; 145 };
149 146
150/* Iterate over the intervals between BEG and END in the tree T. 147/* Iterate over the intervals between BEG and END in the tree T.
151 N will hold successive nodes. ORDER can be one of : `ASCENDING`, 148 N will hold successive nodes. ORDER can be one of : `ASCENDING`,
152 `DESCENDING`, or `PRE_ORDER`. 149 `DESCENDING`, `POST_ORDER`, or `PRE_ORDER`.
153 It should be used as: 150 It should be used as:
154 151
155 ITREE_FOREACH (n, t, beg, end, order) 152 ITREE_FOREACH (n, t, beg, end, order)
@@ -160,9 +157,6 @@ struct itree_iterator
160 BEWARE: 157 BEWARE:
161 - The expression T may be evaluated more than once, so make sure 158 - The expression T may be evaluated more than once, so make sure
162 it is cheap and pure. 159 it is cheap and pure.
163 - If you need to exit the loop early, you *have* to call `ITREE_ABORT`
164 just before exiting (e.g. with `break` or `return`).
165 - Non-local exits are not supported within the body of the loop.
166 - Don't modify the tree during the iteration. 160 - Don't modify the tree during the iteration.
167 */ 161 */
168#define ITREE_FOREACH(n, t, beg, end, order) \ 162#define ITREE_FOREACH(n, t, beg, end, order) \
@@ -179,11 +173,7 @@ struct itree_iterator
179 *itree_iter_ \ 173 *itree_iter_ \
180 = itree_iterator_start (&itree_local_iter_, \ 174 = itree_iterator_start (&itree_local_iter_, \
181 t, beg, end, ITREE_##order); \ 175 t, beg, end, ITREE_##order); \
182 ((n = itree_iterator_next (itree_iter_)) \ 176 ((n = itree_iterator_next (itree_iter_)));)
183 || (itree_iterator_finish (itree_iter_), false));)
184
185#define ITREE_FOREACH_ABORT() \
186 itree_iterator_finish (itree_iter_)
187 177
188#define ITREE_FOREACH_NARROW(beg, end) \ 178#define ITREE_FOREACH_NARROW(beg, end) \
189 itree_iterator_narrow (itree_iter_, beg, end) 179 itree_iterator_narrow (itree_iter_, beg, end)
diff --git a/src/xdisp.c b/src/xdisp.c
index f6a279636a0..414ee9bfe28 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -7036,17 +7036,11 @@ strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
7036 str = Foverlay_get (overlay, Qbefore_string); 7036 str = Foverlay_get (overlay, Qbefore_string);
7037 if (STRINGP (str) && SCHARS (str) 7037 if (STRINGP (str) && SCHARS (str)
7038 && memchr (SDATA (str), '\n', SBYTES (str))) 7038 && memchr (SDATA (str), '\n', SBYTES (str)))
7039 { 7039 return true;
7040 ITREE_FOREACH_ABORT ();
7041 return true;
7042 }
7043 str = Foverlay_get (overlay, Qafter_string); 7040 str = Foverlay_get (overlay, Qafter_string);
7044 if (STRINGP (str) && SCHARS (str) 7041 if (STRINGP (str) && SCHARS (str)
7045 && memchr (SDATA (str), '\n', SBYTES (str))) 7042 && memchr (SDATA (str), '\n', SBYTES (str)))
7046 { 7043 return true;
7047 ITREE_FOREACH_ABORT ();
7048 return true;
7049 }
7050 } 7044 }
7051 7045
7052 /* Check for 'display' properties whose values include strings. */ 7046 /* Check for 'display' properties whose values include strings. */