@@ -114,7 +114,8 @@ class Context {
114114 return part1;
115115 }
116116
117- return _join ('absolute' , [
117+ final args = _validateArgs (
118+ 'absolute' ,
118119 current,
119120 part1,
120121 part2,
@@ -131,7 +132,8 @@ class Context {
131132 part13,
132133 part14,
133134 part15,
134- ]);
135+ );
136+ return joinAll (args);
135137 }
136138
137139 /// Gets the part of [path] after the last separator on the context's
@@ -279,30 +281,27 @@ class Context {
279281 String ? part14,
280282 String ? part15,
281283 String ? part16,
282- ]) =>
283- _join ('join' , [
284- part1,
285- part2,
286- part3,
287- part4,
288- part5,
289- part6,
290- part7,
291- part8,
292- part9,
293- part10,
294- part11,
295- part12,
296- part13,
297- part14,
298- part15,
299- part16,
300- ]);
301-
302- /// Joins the given path parts into a single path.
303- String _join (String method, List <String ?> parts) {
304- _validateArgList (method, parts);
305- return joinAll (parts.whereType <String >());
284+ ]) {
285+ final args = _validateArgs (
286+ 'join' ,
287+ part1,
288+ part2,
289+ part3,
290+ part4,
291+ part5,
292+ part6,
293+ part7,
294+ part8,
295+ part9,
296+ part10,
297+ part11,
298+ part12,
299+ part13,
300+ part14,
301+ part15,
302+ part16,
303+ );
304+ return joinAll (args);
306305 }
307306
308307 /// Joins the given path parts into a single path. Example:
@@ -1165,28 +1164,194 @@ Uri _parseUri(Object uri) {
11651164
11661165/// Validates that there are no non-null arguments following a null one and
11671166/// throws an appropriate [ArgumentError] on failure.
1168- void _validateArgList (String method, List <String ?> args) {
1169- for (var i = 1 ; i < args.length; i++ ) {
1170- // Ignore nulls hanging off the end.
1171- if (args[i] == null || args[i - 1 ] != null ) continue ;
1172-
1173- int numArgs;
1174- for (numArgs = args.length; numArgs >= 1 ; numArgs-- ) {
1175- if (args[numArgs - 1 ] != null ) break ;
1176- }
1167+ ///
1168+ /// This function operates on individual arguments rather than a list for better
1169+ /// performance by avoiding list allocation.
1170+ ///
1171+ /// Returns a list of only the non-null arguments.
1172+ List <String > _validateArgs (
1173+ String method,
1174+ String p0,
1175+ String ? p1,
1176+ String ? p2,
1177+ String ? p3,
1178+ String ? p4,
1179+ String ? p5,
1180+ String ? p6,
1181+ String ? p7,
1182+ String ? p8,
1183+ String ? p9,
1184+ String ? p10,
1185+ String ? p11,
1186+ String ? p12,
1187+ String ? p13,
1188+ String ? p14,
1189+ String ? p15,
1190+ ) {
1191+ // Helper to create the list of args for error messages.
1192+ List <String ?> allArgs () => [
1193+ p0,
1194+ p1,
1195+ p2,
1196+ p3,
1197+ p4,
1198+ p5,
1199+ p6,
1200+ p7,
1201+ p8,
1202+ p9,
1203+ p10,
1204+ p11,
1205+ p12,
1206+ p13,
1207+ p14,
1208+ p15,
1209+ ];
1210+
1211+ // p0 is always non-null (enforced by caller), so we start checking from p1.
1212+ // Once we see a null, all subsequent arguments must also be null.
1213+ var seenNull = false ;
1214+ final args = < String > [p0];
1215+
1216+ if (p1 == null ) {
1217+ seenNull = true ;
1218+ } else {
1219+ args.add (p1);
1220+ }
11771221
1178- // Show the arguments.
1179- final message = StringBuffer ();
1180- message.write ('$method (' );
1181- message.write (
1182- args
1183- .take (numArgs)
1184- .map ((arg) => arg == null ? 'null' : '"$arg "' )
1185- .join (', ' ),
1186- );
1187- message.write ('): part ${i - 1 } was null, but part $i was not.' );
1188- throw ArgumentError (message.toString ());
1222+ if (p2 == null ) {
1223+ seenNull = true ;
1224+ } else if (seenNull) {
1225+ _throwArgError (method, 2 , allArgs ());
1226+ } else {
1227+ args.add (p2);
1228+ }
1229+
1230+ if (p3 == null ) {
1231+ seenNull = true ;
1232+ } else if (seenNull) {
1233+ _throwArgError (method, 3 , allArgs ());
1234+ } else {
1235+ args.add (p3);
11891236 }
1237+
1238+ if (p4 == null ) {
1239+ seenNull = true ;
1240+ } else if (seenNull) {
1241+ _throwArgError (method, 4 , allArgs ());
1242+ } else {
1243+ args.add (p4);
1244+ }
1245+
1246+ if (p5 == null ) {
1247+ seenNull = true ;
1248+ } else if (seenNull) {
1249+ _throwArgError (method, 5 , allArgs ());
1250+ } else {
1251+ args.add (p5);
1252+ }
1253+
1254+ if (p6 == null ) {
1255+ seenNull = true ;
1256+ } else if (seenNull) {
1257+ _throwArgError (method, 6 , allArgs ());
1258+ } else {
1259+ args.add (p6);
1260+ }
1261+
1262+ if (p7 == null ) {
1263+ seenNull = true ;
1264+ } else if (seenNull) {
1265+ _throwArgError (method, 7 , allArgs ());
1266+ } else {
1267+ args.add (p7);
1268+ }
1269+
1270+ if (p8 == null ) {
1271+ seenNull = true ;
1272+ } else if (seenNull) {
1273+ _throwArgError (method, 8 , allArgs ());
1274+ } else {
1275+ args.add (p8);
1276+ }
1277+
1278+ if (p9 == null ) {
1279+ seenNull = true ;
1280+ } else if (seenNull) {
1281+ _throwArgError (method, 9 , allArgs ());
1282+ } else {
1283+ args.add (p9);
1284+ }
1285+
1286+ if (p10 == null ) {
1287+ seenNull = true ;
1288+ } else if (seenNull) {
1289+ _throwArgError (method, 10 , allArgs ());
1290+ } else {
1291+ args.add (p10);
1292+ }
1293+
1294+ if (p11 == null ) {
1295+ seenNull = true ;
1296+ } else if (seenNull) {
1297+ _throwArgError (method, 11 , allArgs ());
1298+ } else {
1299+ args.add (p11);
1300+ }
1301+
1302+ if (p12 == null ) {
1303+ seenNull = true ;
1304+ } else if (seenNull) {
1305+ _throwArgError (method, 12 , allArgs ());
1306+ } else {
1307+ args.add (p12);
1308+ }
1309+
1310+ if (p13 == null ) {
1311+ seenNull = true ;
1312+ } else if (seenNull) {
1313+ _throwArgError (method, 13 , allArgs ());
1314+ } else {
1315+ args.add (p13);
1316+ }
1317+
1318+ if (p14 == null ) {
1319+ seenNull = true ;
1320+ } else if (seenNull) {
1321+ _throwArgError (method, 14 , allArgs ());
1322+ } else {
1323+ args.add (p14);
1324+ }
1325+
1326+ if (p15 == null ) {
1327+ // No more arguments to check after p15, so this is valid.
1328+ } else if (seenNull) {
1329+ _throwArgError (method, 15 , allArgs ());
1330+ } else {
1331+ args.add (p15);
1332+ }
1333+
1334+ return args;
1335+ }
1336+
1337+ /// Throws an [ArgumentError] for invalid argument ordering.
1338+ ///
1339+ /// [nonNullIndex] is the index of the non-null argument that follows a null.
1340+ Never _throwArgError (String method, int nonNullIndex, List <String ?> args) {
1341+ int numArgs;
1342+ for (numArgs = args.length; numArgs >= 1 ; numArgs-- ) {
1343+ if (args[numArgs - 1 ] != null ) break ;
1344+ }
1345+
1346+ final message = StringBuffer ();
1347+ message.write ('$method (' );
1348+ message.write (
1349+ args.take (numArgs).map ((arg) => arg == null ? 'null' : '"$arg "' ).join (', ' ),
1350+ );
1351+ message.write (
1352+ '): part ${nonNullIndex - 1 } was null, but part $nonNullIndex was not.' ,
1353+ );
1354+ throw ArgumentError (message.toString ());
11901355}
11911356
11921357/// An enum of possible return values for [Context._pathDirection] .
0 commit comments