| | 951 | |
|---|
| | 952 | XPath support |
|---|
| | 953 | |
|---|
| | 954 | Provides support for common XPath axis and filtering functions, |
|---|
| | 955 | via a native-D interface instead of typical interpreted notation. |
|---|
| | 956 | |
|---|
| | 957 | The general idea here is to generate a NodeSet consisting of those |
|---|
| | 958 | tree-nodes which satisfy a filtering function. The direction, or |
|---|
| | 959 | axis, of tree traversal is governed by one of several predefined |
|---|
| | 960 | operations. All methods facilitiate call-chaining, where each step |
|---|
| | 961 | returns a new NodeSet instance to be operated upon. |
|---|
| | 962 | |
|---|
| | 963 | The set of nodes themselves are collected in a freelist, avoiding |
|---|
| | 964 | heap-activity and making good use of D array-slicing facilities. |
|---|
| | 965 | |
|---|
| | 966 | (this needs to be a class in order to avoid forward-ref issues) |
|---|
| | 967 | |
|---|
| | 968 | *******************************************************************************/ |
|---|
| | 969 | |
|---|
| | 970 | private class XmlPath(T) |
|---|
| | 971 | { |
|---|
| | 972 | public alias Document!(T) Doc; /// the typed document |
|---|
| | 973 | public alias Doc.Node Node; /// generic document node |
|---|
| | 974 | |
|---|
| | 975 | private Node[] freelist; |
|---|
| | 976 | private uint freeIndex, |
|---|
| | 977 | markIndex; |
|---|
| | 978 | private uint recursion; |
|---|
| | 979 | |
|---|
| | 980 | /*********************************************************************** |
|---|
| | 981 | |
|---|
| | 982 | Prime a query |
|---|
| | 983 | |
|---|
| | 984 | Returns a NodeSet containing just the given node, which |
|---|
| | 985 | can then be used to cascade results into subsequent NodeSet |
|---|
| | 986 | instances. |
|---|
| | 987 | |
|---|
| | 988 | ***********************************************************************/ |
|---|
| | 989 | |
|---|
| | 990 | final NodeSet start (Node root) |
|---|
| | 991 | { |
|---|
| | 992 | // we have to support recursion which may occur within |
|---|
| | 993 | // a filter callback |
|---|
| | 994 | if (recursion is 0) |
|---|
| | 995 | { |
|---|
| | 996 | if (freelist.length is 0) |
|---|
| | 997 | freelist.length = 256; |
|---|
| | 998 | freeIndex = 0; |
|---|
| | 999 | } |
|---|
| | 1000 | |
|---|
| | 1001 | NodeSet set = {this}; |
|---|
| | 1002 | auto mark = freeIndex; |
|---|
| | 1003 | allocate(root); |
|---|
| | 1004 | return set.assign (mark); |
|---|
| | 1005 | |
|---|
| | 1006 | } |
|---|
| | 1007 | |
|---|
| | 1008 | /*********************************************************************** |
|---|
| | 1009 | |
|---|
| | 1010 | This is the meat of XPath support. All of the NodeSet |
|---|
| | 1011 | operators exist here, in order to enable call-chaining. |
|---|
| | 1012 | |
|---|
| | 1013 | Note that some of the axis do double-duty as a filter |
|---|
| | 1014 | also. This is just a convenience factor, and doesn't |
|---|
| | 1015 | change the underlying mechanisms. |
|---|
| | 1016 | |
|---|
| | 1017 | ***********************************************************************/ |
|---|
| | 1018 | |
|---|
| | 1019 | struct NodeSet |
|---|
| | 1020 | { |
|---|
| | 1021 | private XmlPath host; |
|---|
| | 1022 | private Node[] members; |
|---|
| | 1023 | |
|---|
| | 1024 | /*************************************************************** |
|---|
| | 1025 | |
|---|
| | 1026 | Return the number of selected nodes in the set |
|---|
| | 1027 | |
|---|
| | 1028 | ***************************************************************/ |
|---|
| | 1029 | |
|---|
| | 1030 | uint count () |
|---|
| | 1031 | { |
|---|
| | 1032 | return members.length; |
|---|
| | 1033 | } |
|---|
| | 1034 | |
|---|
| | 1035 | /*************************************************************** |
|---|
| | 1036 | |
|---|
| | 1037 | Return a set containing just the first node of |
|---|
| | 1038 | the current set |
|---|
| | 1039 | |
|---|
| | 1040 | ***************************************************************/ |
|---|
| | 1041 | |
|---|
| | 1042 | NodeSet first () |
|---|
| | 1043 | { |
|---|
| | 1044 | return nth (0); |
|---|
| | 1045 | } |
|---|
| | 1046 | |
|---|
| | 1047 | /*************************************************************** |
|---|
| | 1048 | |
|---|
| | 1049 | Return a set containing just the last node of |
|---|
| | 1050 | the current set |
|---|
| | 1051 | |
|---|
| | 1052 | ***************************************************************/ |
|---|
| | 1053 | |
|---|
| | 1054 | NodeSet last () |
|---|
| | 1055 | { |
|---|
| | 1056 | auto i = members.length; |
|---|
| | 1057 | if (i > 0) |
|---|
| | 1058 | --i; |
|---|
| | 1059 | return nth (i); |
|---|
| | 1060 | } |
|---|
| | 1061 | |
|---|
| | 1062 | /*************************************************************** |
|---|
| | 1063 | |
|---|
| | 1064 | Return a set containing just the nth node of |
|---|
| | 1065 | the current set |
|---|
| | 1066 | |
|---|
| | 1067 | ***************************************************************/ |
|---|
| | 1068 | |
|---|
| | 1069 | NodeSet opIndex (uint i) |
|---|
| | 1070 | { |
|---|
| | 1071 | return nth (i); |
|---|
| | 1072 | } |
|---|
| | 1073 | |
|---|
| | 1074 | /*************************************************************** |
|---|
| | 1075 | |
|---|
| | 1076 | Return a set containing just the nth node of |
|---|
| | 1077 | the current set |
|---|
| | 1078 | |
|---|
| | 1079 | ***************************************************************/ |
|---|
| | 1080 | |
|---|
| | 1081 | NodeSet nth (uint index) |
|---|
| | 1082 | { |
|---|
| | 1083 | NodeSet set = {host}; |
|---|
| | 1084 | auto mark = host.mark; |
|---|
| | 1085 | if (index < members.length) |
|---|
| | 1086 | host.allocate (members [index]); |
|---|
| | 1087 | return set.assign (mark); |
|---|
| | 1088 | } |
|---|
| | 1089 | |
|---|
| | 1090 | /*************************************************************** |
|---|
| | 1091 | |
|---|
| | 1092 | Return a set containing all child elements of the |
|---|
| | 1093 | nodes within this set |
|---|
| | 1094 | |
|---|
| | 1095 | ***************************************************************/ |
|---|
| | 1096 | |
|---|
| | 1097 | NodeSet opSlice () |
|---|
| | 1098 | { |
|---|
| | 1099 | return child(); |
|---|
| | 1100 | } |
|---|
| | 1101 | |
|---|
| | 1102 | /*************************************************************** |
|---|
| | 1103 | |
|---|
| | 1104 | Return a set containing all child elements of the |
|---|
| | 1105 | nodes within this set, which match the given name |
|---|
| | 1106 | |
|---|
| | 1107 | ***************************************************************/ |
|---|
| | 1108 | |
|---|
| | 1109 | NodeSet opIndex (T[] name) |
|---|
| | 1110 | { |
|---|
| | 1111 | return child (name); |
|---|
| | 1112 | } |
|---|
| | 1113 | |
|---|
| | 1114 | /*************************************************************** |
|---|
| | 1115 | |
|---|
| | 1116 | Return a set containing all child elements of the |
|---|
| | 1117 | nodes within this set |
|---|
| | 1118 | |
|---|
| | 1119 | ***************************************************************/ |
|---|
| | 1120 | |
|---|
| | 1121 | NodeSet child () |
|---|
| | 1122 | { |
|---|
| | 1123 | return child ((Node node) |
|---|
| | 1124 | {return node.type is XmlNodeType.Element;}); |
|---|
| | 1125 | } |
|---|
| | 1126 | |
|---|
| | 1127 | /*************************************************************** |
|---|
| | 1128 | |
|---|
| | 1129 | Return a set containing all child elements of the |
|---|
| | 1130 | nodes within this set, which match the given name |
|---|
| | 1131 | |
|---|
| | 1132 | ***************************************************************/ |
|---|
| | 1133 | |
|---|
| | 1134 | NodeSet child (T[] name) |
|---|
| | 1135 | { |
|---|
| | 1136 | return child ((Node node) |
|---|
| | 1137 | {return node.type is XmlNodeType.Element && |
|---|
| | 1138 | node.name == name;}); |
|---|
| | 1139 | } |
|---|
| | 1140 | |
|---|
| | 1141 | /*************************************************************** |
|---|
| | 1142 | |
|---|
| | 1143 | Return a set containing all parent elements of the |
|---|
| | 1144 | nodes within this set, which match the optional name |
|---|
| | 1145 | |
|---|
| | 1146 | ***************************************************************/ |
|---|
| | 1147 | |
|---|
| | 1148 | NodeSet parent (T[] name = null) |
|---|
| | 1149 | { |
|---|
| | 1150 | return parent ((Node node) |
|---|
| | 1151 | {return name.ptr is null || |
|---|
| | 1152 | node.name == name;}); |
|---|
| | 1153 | } |
|---|
| | 1154 | |
|---|
| | 1155 | /*************************************************************** |
|---|
| | 1156 | |
|---|
| | 1157 | Return a set containing all text nodes of the |
|---|
| | 1158 | nodes within this set |
|---|
| | 1159 | |
|---|
| | 1160 | ***************************************************************/ |
|---|
| | 1161 | |
|---|
| | 1162 | NodeSet text () |
|---|
| | 1163 | { |
|---|
| | 1164 | return child ((Node node) |
|---|
| | 1165 | {return node.type is XmlNodeType.Data;}); |
|---|
| | 1166 | } |
|---|
| | 1167 | |
|---|
| | 1168 | /*************************************************************** |
|---|
| | 1169 | |
|---|
| | 1170 | Return a set containing all text nodes of the |
|---|
| | 1171 | nodes within this set, which have a matching value |
|---|
| | 1172 | |
|---|
| | 1173 | ***************************************************************/ |
|---|
| | 1174 | |
|---|
| | 1175 | NodeSet text (T[] value) |
|---|
| | 1176 | { |
|---|
| | 1177 | return child ((Node node) |
|---|
| | 1178 | {return node.type is XmlNodeType.Data && |
|---|
| | 1179 | node.value == value;}); |
|---|
| | 1180 | } |
|---|
| | 1181 | |
|---|
| | 1182 | /*************************************************************** |
|---|
| | 1183 | |
|---|
| | 1184 | Return a set containing all attributes of the |
|---|
| | 1185 | nodes within this set, which have a matching value |
|---|
| | 1186 | |
|---|
| | 1187 | ***************************************************************/ |
|---|
| | 1188 | |
|---|
| | 1189 | NodeSet attribute () |
|---|
| | 1190 | { |
|---|
| | 1191 | return attributes ((Node node) |
|---|
| | 1192 | {return node.type is XmlNodeType.Attribute;}); |
|---|
| | 1193 | } |
|---|
| | 1194 | |
|---|
| | 1195 | /*************************************************************** |
|---|
| | 1196 | |
|---|
| | 1197 | Return a set containing all attributes of the |
|---|
| | 1198 | nodes within this set, which have a matching name |
|---|
| | 1199 | |
|---|
| | 1200 | ***************************************************************/ |
|---|
| | 1201 | |
|---|
| | 1202 | NodeSet attribute (T[] name) |
|---|
| | 1203 | { |
|---|
| | 1204 | return attributes ((Node node) |
|---|
| | 1205 | {return node.type is XmlNodeType.Attribute && |
|---|
| | 1206 | node.name == name;}); |
|---|
| | 1207 | } |
|---|
| | 1208 | |
|---|
| | 1209 | /*************************************************************** |
|---|
| | 1210 | |
|---|
| | 1211 | Return a set containing all descendant elements of |
|---|
| | 1212 | the nodes within this set |
|---|
| | 1213 | |
|---|
| | 1214 | ***************************************************************/ |
|---|
| | 1215 | |
|---|
| | 1216 | NodeSet descendant () |
|---|
| | 1217 | { |
|---|
| | 1218 | return descendant ((Node node) |
|---|
| | 1219 | {return node.type is XmlNodeType.Element;}); |
|---|
| | 1220 | } |
|---|
| | 1221 | |
|---|
| | 1222 | /*************************************************************** |
|---|
| | 1223 | |
|---|
| | 1224 | Return a set containing all descendant elements of |
|---|
| | 1225 | the nodes within this set, which match the given name |
|---|
| | 1226 | |
|---|
| | 1227 | ***************************************************************/ |
|---|
| | 1228 | |
|---|
| | 1229 | NodeSet descendant (T[] name) |
|---|
| | 1230 | { |
|---|
| | 1231 | return descendant ((Node node) |
|---|
| | 1232 | {return node.type is XmlNodeType.Element && |
|---|
| | 1233 | node.name == name;}); |
|---|
| | 1234 | } |
|---|
| | 1235 | |
|---|
| | 1236 | /*************************************************************** |
|---|
| | 1237 | |
|---|
| | 1238 | Return a set containing all ancestor elements of |
|---|
| | 1239 | the nodes within this set, which match the optional |
|---|
| | 1240 | name |
|---|
| | 1241 | |
|---|
| | 1242 | ***************************************************************/ |
|---|
| | 1243 | |
|---|
| | 1244 | NodeSet ancestor (T[] name = null) |
|---|
| | 1245 | { |
|---|
| | 1246 | return ancestor ((Node node) |
|---|
| | 1247 | {return name.ptr is null || |
|---|
| | 1248 | node.name == name;}); |
|---|
| | 1249 | } |
|---|
| | 1250 | |
|---|
| | 1251 | /*************************************************************** |
|---|
| | 1252 | |
|---|
| | 1253 | Return a set containing all prior sibling elements of |
|---|
| | 1254 | the nodes within this set, which match the optional |
|---|
| | 1255 | name |
|---|
| | 1256 | |
|---|
| | 1257 | ***************************************************************/ |
|---|
| | 1258 | |
|---|
| | 1259 | NodeSet prev (T[] name = null) |
|---|
| | 1260 | { |
|---|
| | 1261 | return prev ((Node node) |
|---|
| | 1262 | {return node.type is XmlNodeType.Element && |
|---|
| | 1263 | (name.ptr is null || |
|---|
| | 1264 | node.name == name);}); |
|---|
| | 1265 | } |
|---|
| | 1266 | |
|---|
| | 1267 | /*************************************************************** |
|---|
| | 1268 | |
|---|
| | 1269 | Return a set containing all subsequent sibling |
|---|
| | 1270 | elements of the nodes within this set, which |
|---|
| | 1271 | match the optional name |
|---|
| | 1272 | |
|---|
| | 1273 | ***************************************************************/ |
|---|
| | 1274 | |
|---|
| | 1275 | NodeSet next (T[] name = null) |
|---|
| | 1276 | { |
|---|
| | 1277 | return next ((Node node) |
|---|
| | 1278 | {return node.type is XmlNodeType.Element && |
|---|
| | 1279 | (name.ptr is null || |
|---|
| | 1280 | node.name == name);}); |
|---|
| | 1281 | } |
|---|
| | 1282 | |
|---|
| | 1283 | /*************************************************************** |
|---|
| | 1284 | |
|---|
| | 1285 | Return a set containing all nodes within this set |
|---|
| | 1286 | which pass the filtering test |
|---|
| | 1287 | |
|---|
| | 1288 | ***************************************************************/ |
|---|
| | 1289 | |
|---|
| | 1290 | NodeSet filter (bool delegate(Node) filter) |
|---|
| | 1291 | { |
|---|
| | 1292 | NodeSet set = {host}; |
|---|
| | 1293 | auto mark = host.mark; |
|---|
| | 1294 | foreach (member; members) |
|---|
| | 1295 | test (filter, member); |
|---|
| | 1296 | return set.assign (mark); |
|---|
| | 1297 | } |
|---|
| | 1298 | |
|---|
| | 1299 | /*************************************************************** |
|---|
| | 1300 | |
|---|
| | 1301 | Return a set containing all child nodes of |
|---|
| | 1302 | the nodes within this set which pass the |
|---|
| | 1303 | filtering test |
|---|
| | 1304 | |
|---|
| | 1305 | ***************************************************************/ |
|---|
| | 1306 | |
|---|
| | 1307 | NodeSet child (bool delegate(Node) filter) |
|---|
| | 1308 | { |
|---|
| | 1309 | NodeSet set = {host}; |
|---|
| | 1310 | auto mark = host.mark; |
|---|
| | 1311 | foreach (parent; members) |
|---|
| | 1312 | foreach (child; parent.children) |
|---|
| | 1313 | test (filter, child); |
|---|
| | 1314 | return set.assign (mark); |
|---|
| | 1315 | } |
|---|
| | 1316 | |
|---|
| | 1317 | /*************************************************************** |
|---|
| | 1318 | |
|---|
| | 1319 | Return a set containing all parent nodes of |
|---|
| | 1320 | the nodes within this set which pass the given |
|---|
| | 1321 | filtering test |
|---|
| | 1322 | |
|---|
| | 1323 | ***************************************************************/ |
|---|
| | 1324 | |
|---|
| | 1325 | NodeSet parent (bool delegate(Node) filter) |
|---|
| | 1326 | { |
|---|
| | 1327 | NodeSet set = {host}; |
|---|
| | 1328 | auto mark = host.mark; |
|---|
| | 1329 | foreach (member; members) |
|---|
| | 1330 | { |
|---|
| | 1331 | auto p = member.parent; |
|---|
| | 1332 | if (p && p.type != XmlNodeType.Document) |
|---|
| | 1333 | test (filter, p); |
|---|
| | 1334 | } |
|---|
| | 1335 | return set.assign (mark); |
|---|
| | 1336 | } |
|---|
| | 1337 | |
|---|
| | 1338 | /*************************************************************** |
|---|
| | 1339 | |
|---|
| | 1340 | Return a set containing all attribute nodes of |
|---|
| | 1341 | the nodes within this set which pass the given |
|---|
| | 1342 | filtering test |
|---|
| | 1343 | |
|---|
| | 1344 | ***************************************************************/ |
|---|
| | 1345 | |
|---|
| | 1346 | NodeSet attributes (bool delegate(Node) filter) |
|---|
| | 1347 | { |
|---|
| | 1348 | NodeSet set = {host}; |
|---|
| | 1349 | auto mark = host.mark; |
|---|
| | 1350 | foreach (member; members) |
|---|
| | 1351 | foreach (attr; member.attributes) |
|---|
| | 1352 | test (filter, attr); |
|---|
| | 1353 | return set.assign (mark); |
|---|
| | 1354 | } |
|---|
| | 1355 | |
|---|
| | 1356 | /*************************************************************** |
|---|
| | 1357 | |
|---|
| | 1358 | Return a set containing all descendant nodes of |
|---|
| | 1359 | the nodes within this set, which pass the given |
|---|
| | 1360 | filtering test |
|---|
| | 1361 | |
|---|
| | 1362 | ***************************************************************/ |
|---|
| | 1363 | |
|---|
| | 1364 | NodeSet descendant (bool delegate(Node) filter) |
|---|
| | 1365 | { |
|---|
| | 1366 | void traverse (Node parent) |
|---|
| | 1367 | { |
|---|
| | 1368 | foreach (child; parent.children) |
|---|
| | 1369 | { |
|---|
| | 1370 | test (filter, child); |
|---|
| | 1371 | traverse (child); |
|---|
| | 1372 | } |
|---|
| | 1373 | } |
|---|
| | 1374 | |
|---|
| | 1375 | NodeSet set = {host}; |
|---|
| | 1376 | auto mark = host.mark; |
|---|
| | 1377 | |
|---|
| | 1378 | foreach (member; members) |
|---|
| | 1379 | traverse (member); |
|---|
| | 1380 | |
|---|
| | 1381 | return set.assign (mark); |
|---|
| | 1382 | } |
|---|
| | 1383 | |
|---|
| | 1384 | /*************************************************************** |
|---|
| | 1385 | |
|---|
| | 1386 | Return a set containing all ancestor nodes of |
|---|
| | 1387 | the nodes within this set, which pass the given |
|---|
| | 1388 | filtering test |
|---|
| | 1389 | |
|---|
| | 1390 | ***************************************************************/ |
|---|
| | 1391 | |
|---|
| | 1392 | NodeSet ancestor (bool delegate(Node) filter) |
|---|
| | 1393 | { |
|---|
| | 1394 | void traverse (Node child) |
|---|
| | 1395 | { |
|---|
| | 1396 | auto p = child.parent_; |
|---|
| | 1397 | if (p && p.type != XmlNodeType.Document) |
|---|
| | 1398 | { |
|---|
| | 1399 | test (filter, p); |
|---|
| | 1400 | traverse (p); |
|---|
| | 1401 | } |
|---|
| | 1402 | } |
|---|
| | 1403 | |
|---|
| | 1404 | NodeSet set = {host}; |
|---|
| | 1405 | auto mark = host.mark; |
|---|
| | 1406 | |
|---|
| | 1407 | foreach (member; members) |
|---|
| | 1408 | traverse (member); |
|---|
| | 1409 | |
|---|
| | 1410 | return set.assign (mark); |
|---|
| | 1411 | } |
|---|
| | 1412 | |
|---|
| | 1413 | /*************************************************************** |
|---|
| | 1414 | |
|---|
| | 1415 | Return a set containing all following siblings |
|---|
| | 1416 | of the ones within this set, which pass the given |
|---|
| | 1417 | filtering test |
|---|
| | 1418 | |
|---|
| | 1419 | ***************************************************************/ |
|---|
| | 1420 | |
|---|
| | 1421 | NodeSet next (bool delegate(Node) filter) |
|---|
| | 1422 | { |
|---|
| | 1423 | NodeSet set = {host}; |
|---|
| | 1424 | auto mark = host.mark; |
|---|
| | 1425 | foreach (member; members) |
|---|
| | 1426 | { |
|---|
| | 1427 | auto p = member.nextSibling_; |
|---|
| | 1428 | while (p) |
|---|
| | 1429 | { |
|---|
| | 1430 | test (filter, p); |
|---|
| | 1431 | p = p.nextSibling_; |
|---|
| | 1432 | } |
|---|
| | 1433 | } |
|---|
| | 1434 | return set.assign (mark); |
|---|
| | 1435 | } |
|---|
| | 1436 | |
|---|
| | 1437 | /*************************************************************** |
|---|
| | 1438 | |
|---|
| | 1439 | Return a set containing all prior sibling nodes |
|---|
| | 1440 | of the ones within this set, which pass the given |
|---|
| | 1441 | filtering test |
|---|
| | 1442 | |
|---|
| | 1443 | ***************************************************************/ |
|---|
| | 1444 | |
|---|
| | 1445 | NodeSet prev (bool delegate(Node) filter) |
|---|
| | 1446 | { |
|---|
| | 1447 | NodeSet set = {host}; |
|---|
| | 1448 | auto mark = host.mark; |
|---|
| | 1449 | foreach (member; members) |
|---|
| | 1450 | { |
|---|
| | 1451 | auto p = member.prevSibling_; |
|---|
| | 1452 | while (p) |
|---|
| | 1453 | { |
|---|
| | 1454 | test (filter, p); |
|---|
| | 1455 | p = p.prevSibling_; |
|---|
| | 1456 | } |
|---|
| | 1457 | } |
|---|
| | 1458 | return set.assign (mark); |
|---|
| | 1459 | } |
|---|
| | 1460 | |
|---|
| | 1461 | /*************************************************************** |
|---|
| | 1462 | |
|---|
| | 1463 | Traverse the members of this set |
|---|
| | 1464 | |
|---|
| | 1465 | ***************************************************************/ |
|---|
| | 1466 | |
|---|
| | 1467 | int opApply (int delegate(inout Node) dg) |
|---|
| | 1468 | { |
|---|
| | 1469 | int ret; |
|---|
| | 1470 | foreach (member; members) |
|---|
| | 1471 | if ((ret = dg (member)) != 0) |
|---|
| | 1472 | break; |
|---|
| | 1473 | return ret; |
|---|
| | 1474 | } |
|---|
| | 1475 | |
|---|
| | 1476 | /*************************************************************** |
|---|
| | 1477 | |
|---|
| | 1478 | Assign a slice of the freelist to this NodeSet |
|---|
| | 1479 | |
|---|
| | 1480 | ***************************************************************/ |
|---|
| | 1481 | |
|---|
| | 1482 | private NodeSet assign (uint mark) |
|---|
| | 1483 | { |
|---|
| | 1484 | members = host.slice (mark); |
|---|
| | 1485 | return *this; |
|---|
| | 1486 | } |
|---|
| | 1487 | |
|---|
| | 1488 | /*************************************************************** |
|---|
| | 1489 | |
|---|
| | 1490 | Execute a filter on the given node. We have to |
|---|
| | 1491 | deal with potential query recusion, so we set |
|---|
| | 1492 | all kinda crap to recover from that |
|---|
| | 1493 | |
|---|
| | 1494 | ***************************************************************/ |
|---|
| | 1495 | |
|---|
| | 1496 | private void test (bool delegate(Node) filter, Node node) |
|---|
| | 1497 | { |
|---|
| | 1498 | ++host.recursion; |
|---|
| | 1499 | auto pop = host.freeIndex; |
|---|
| | 1500 | auto add = filter (node); |
|---|
| | 1501 | host.freeIndex = pop; |
|---|
| | 1502 | --host.recursion; |
|---|
| | 1503 | if (add) |
|---|
| | 1504 | host.allocate (node); |
|---|
| | 1505 | } |
|---|
| | 1506 | } |
|---|
| | 1507 | |
|---|
| | 1508 | /*********************************************************************** |
|---|
| | 1509 | |
|---|
| | 1510 | Return the current freelist index |
|---|
| | 1511 | |
|---|
| | 1512 | ***********************************************************************/ |
|---|
| | 1513 | |
|---|
| | 1514 | private uint mark () |
|---|
| | 1515 | { |
|---|
| | 1516 | return freeIndex; |
|---|
| | 1517 | } |
|---|
| | 1518 | |
|---|
| | 1519 | /*********************************************************************** |
|---|
| | 1520 | |
|---|
| | 1521 | Return a slice of the freelist |
|---|
| | 1522 | |
|---|
| | 1523 | ***********************************************************************/ |
|---|
| | 1524 | |
|---|
| | 1525 | private Node[] slice (uint mark) |
|---|
| | 1526 | { |
|---|
| | 1527 | assert (mark <= freeIndex); |
|---|
| | 1528 | return freelist [mark .. freeIndex]; |
|---|
| | 1529 | } |
|---|
| | 1530 | |
|---|
| | 1531 | /*********************************************************************** |
|---|
| | 1532 | |
|---|
| | 1533 | Allocate an entry in the freelist, expanding as necessary |
|---|
| | 1534 | |
|---|
| | 1535 | ***********************************************************************/ |
|---|
| | 1536 | |
|---|
| | 1537 | private uint allocate (Node node) |
|---|
| | 1538 | { |
|---|
| | 1539 | if (freeIndex >= freelist.length) |
|---|
| | 1540 | freelist.length = freelist.length + freelist.length / 2; |
|---|
| | 1541 | |
|---|
| | 1542 | freelist[freeIndex] = node; |
|---|
| | 1543 | return ++freeIndex; |
|---|
| | 1544 | } |
|---|
| | 1545 | } |
|---|
| | 1546 | |
|---|
| | 1547 | |
|---|
| | 1548 | |
|---|
| | 1549 | /******************************************************************************* |
|---|
| | 1550 | |
|---|
| | 1551 | Specification for an XML serializer |
|---|