@@ -434,17 +434,13 @@ bool HasVector(const Variant& variant) {
434
434
return false ;
435
435
}
436
436
437
- bool ParseInteger (const char * str, int32_t * output) {
437
+ bool ParseInteger (const char * str, int64_t * output) {
438
438
assert (output);
439
439
assert (str);
440
- // Integers must not have leading zeroes.
441
- if (str[0 ] == ' 0' && str[1 ] != ' \0 ' ) {
442
- return false ;
443
- }
444
440
// Check if the key is numeric
445
441
bool is_int = false ;
446
442
char * end_ptr = nullptr ;
447
- int32_t parse_value = strtol (str, &end_ptr, 10 ); // NOLINT
443
+ int64_t parse_value = strtoll (str, &end_ptr, 10 ); // NOLINT
448
444
if (end_ptr != nullptr && end_ptr != str && *end_ptr == ' \0 ' ) {
449
445
is_int = true ;
450
446
*output = parse_value;
@@ -454,7 +450,7 @@ bool ParseInteger(const char* str, int32_t* output) {
454
450
455
451
// A Variant map can be converted into a Variant vector if:
456
452
// 1. map is not empty and
457
- // 2. All the key are numeric and
453
+ // 2. All the key are integer (no leading 0) and
458
454
// 3. If less or equal to half of the keys in the array is missing.
459
455
// Return whether the map can be converted into a vector, and output
460
456
// max_index_out as the highest numeric key found in the map.
@@ -464,8 +460,14 @@ bool CanConvertVariantMapToVector(const Variant& variant,
464
460
465
461
int64_t max_index = -1 ;
466
462
for (auto & it_child : variant.map ()) {
463
+ assert (it_child.first .is_string ());
464
+ // Integers must not have leading zeroes.
465
+ if (it_child.first .string_value ()[0 ] == ' 0' &&
466
+ it_child.first .string_value ()[1 ] != ' \0 ' ) {
467
+ return false ;
468
+ }
467
469
// Check if the key is numeric
468
- int32_t parse_value = 0 ;
470
+ int64_t parse_value = 0 ;
469
471
bool is_number = ParseInteger (it_child.first .string_value (), &parse_value);
470
472
if (!is_number || parse_value < 0 ) {
471
473
// If any one of the key is not numeric, there is no need to verify
@@ -835,26 +837,55 @@ UtilLeafType GetLeafType(Variant::Type type) {
835
837
// Store the pointers to the key and the value Variant in a map for sorting
836
838
typedef std::pair<const Variant*, const Variant*> NodeSortingData;
837
839
838
- // Comparer for std::sort to sort nodes by key as numeric value
839
- // Return true if right node is greater than left node
840
- bool KeyAsNumberSortingFunction (const NodeSortingData& left,
841
- const NodeSortingData& right) {
842
- return left.first ->AsInt64 ().int64_value () <
843
- right.first ->AsInt64 ().int64_value ();
840
+ int ChildKeyCompareTo (const Variant& left, const Variant& right) {
841
+ const Variant kMinChildKey (QueryParamsComparator::kMinKey );
842
+ const Variant kMaxChildKey (QueryParamsComparator::kMaxKey );
843
+
844
+ FIREBASE_DEV_ASSERT (left.is_string ());
845
+ FIREBASE_DEV_ASSERT (right.is_string ());
846
+
847
+ if (left == right) {
848
+ return 0 ;
849
+ } else if (left == kMinChildKey || right == kMaxChildKey ) {
850
+ return -1 ;
851
+ } else if (right == kMinChildKey || left == kMaxChildKey ) {
852
+ return 1 ;
853
+ } else {
854
+ int64_t left_int_key = -1 ;
855
+ bool left_is_int = ParseInteger (left.string_value (), &left_int_key);
856
+ int64_t right_int_key = -1 ;
857
+ bool right_is_int = ParseInteger (right.string_value (), &right_int_key);
858
+ if (left_is_int) {
859
+ if (right_is_int) {
860
+ int cmp = left_int_key - right_int_key;
861
+ return cmp == 0 ? (strlen (left.string_value ()) -
862
+ strlen (right.string_value ()))
863
+ : cmp;
864
+ } else {
865
+ return -1 ;
866
+ }
867
+ } else if (right_is_int) {
868
+ return 1 ;
869
+ } else {
870
+ return left > right ? 1 : -1 ;
871
+ }
872
+ }
844
873
}
845
874
846
875
// Private function to serialize all child nodes
847
876
void ProcessChildNodes (std::stringstream* ss,
848
- std::vector<NodeSortingData>* nodes, bool saw_priority,
849
- bool can_convert_vector) {
877
+ std::vector<NodeSortingData>* nodes, bool saw_priority) {
850
878
// If any node has priority, sort using priority.
851
879
if (saw_priority) {
852
880
QueryParams params;
853
881
assert (params.order_by == QueryParams::kOrderByPriority );
854
882
std::sort (nodes->begin (), nodes->end (), QueryParamsLesser (¶ms));
855
- } else if (can_convert_vector) {
856
- // If the nodes can be converted to a vector, sort using key as number.
857
- std::sort (nodes->begin (), nodes->end (), KeyAsNumberSortingFunction);
883
+ } else {
884
+ // Otherwise, use default sorting function.
885
+ std::sort (nodes->begin (), nodes->end (),
886
+ [](const NodeSortingData& left, const NodeSortingData& right) {
887
+ return ChildKeyCompareTo (*left.first , *right.first ) < 0 ;
888
+ });
858
889
}
859
890
860
891
// Serialize each child with its key and its hashed value
@@ -888,16 +919,15 @@ void AppendHashRepAsContainer(std::stringstream* ss, const Variant& data) {
888
919
saw_priority =
889
920
saw_priority || !GetVariantPriority (data.vector ()[i]).is_null ();
890
921
}
891
- ProcessChildNodes (ss, &nodes, saw_priority, true );
922
+ ProcessChildNodes (ss, &nodes, saw_priority);
892
923
} else if (data.is_map ()) {
893
924
bool saw_priority = false ;
894
925
for (auto & it_child : data.map ()) {
895
926
nodes.push_back (NodeSortingData (&it_child.first , &it_child.second ));
896
927
saw_priority =
897
928
saw_priority || !GetVariantPriority (it_child.second ).is_null ();
898
929
}
899
- bool can_convert_vector = CanConvertVariantMapToVector (data, nullptr );
900
- ProcessChildNodes (ss, &nodes, saw_priority, can_convert_vector);
930
+ ProcessChildNodes (ss, &nodes, saw_priority);
901
931
}
902
932
}
903
933
0 commit comments