diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index b5cc8d712..5861bd49d 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -1705,9 +1705,20 @@ scan_number_done: // nothing below calls unget() get(); - while (current == ' ' || current == '\t' || current == '\n' || current == '\r') + // this is written as an if-guarded do-while (rather than a plain + // while loop) because that shape is what lets both GCC and Clang + // keep the input adapter's read pointer in a register across + // iterations; the equivalent while-loop measurably defeated that + // optimization in testing, turning long whitespace runs (e.g. the + // indentation of pretty-printed JSON) from a register-only loop + // into one that reloads the pointer from memory every character + if (current == ' ' || current == '\t' || current == '\n' || current == '\r') { - get_ignoring_pending_unget(); + do + { + get_ignoring_pending_unget(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5532ce752..2a787ce8a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -9488,9 +9488,20 @@ scan_number_done: // nothing below calls unget() get(); - while (current == ' ' || current == '\t' || current == '\n' || current == '\r') + // this is written as an if-guarded do-while (rather than a plain + // while loop) because that shape is what lets both GCC and Clang + // keep the input adapter's read pointer in a register across + // iterations; the equivalent while-loop measurably defeated that + // optimization in testing, turning long whitespace runs (e.g. the + // indentation of pretty-printed JSON) from a register-only loop + // into one that reloads the pointer from memory every character + if (current == ' ' || current == '\t' || current == '\n' || current == '\r') { - get_ignoring_pending_unget(); + do + { + get_ignoring_pending_unget(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); } }