@@ -452,43 +452,50 @@ bool ParseInteger(const char* str, int32_t* output) {
452
452
return is_int;
453
453
}
454
454
455
- // Convert one level of map to vector if applicable.
456
- // Convert map to vector if:
455
+ // A Variant map can be converted into a Variant vector if:
457
456
// 1. map is not empty and
458
457
// 2. All the key are numeric and
459
458
// 3. If less or equal to half of the keys in the array is missing.
459
+ // Return whether the map can be converted into a vector, and output
460
+ // max_index_out as the highest numeric key found in the map.
461
+ bool CanConvertVariantMapToVector (const Variant& variant,
462
+ int64_t * max_index_out) {
463
+ if (!variant.is_map () || variant.map ().empty ()) return false ;
464
+
465
+ int64_t max_index = -1 ;
466
+ for (auto & it_child : variant.map ()) {
467
+ // Check if the key is numeric
468
+ int32_t parse_value = 0 ;
469
+ bool is_number = ParseInteger (it_child.first .string_value (), &parse_value);
470
+ if (!is_number || parse_value < 0 ) {
471
+ // If any one of the key is not numeric, there is no need to verify
472
+ // other keys
473
+ return false ;
474
+ }
475
+ max_index = max_index < parse_value ? parse_value : max_index;
476
+ }
477
+
478
+ if (max_index_out) *max_index_out = max_index;
479
+ return max_index < (2 * variant.map ().size ());
480
+ }
481
+
482
+ // Convert one level of map to vector if applicable.
460
483
// This function assume no priority information remains in the variant.
461
484
void ConvertMapToVector (Variant* variant) {
462
485
assert (variant);
463
486
464
- if (variant->is_map () && !variant->map ().empty ()) {
465
- int64_t max_index = -1 ;
466
- for (auto & it_child : variant->map ()) {
467
- // Check if the key is numeric
468
- int32_t parse_value = 0 ;
469
- bool is_number =
470
- ParseInteger (it_child.first .string_value (), &parse_value);
471
- if (!is_number || parse_value < 0 ) {
472
- // If any one of the key is not numeric, there is no need to verify
473
- // other keys
474
- return ;
475
- }
476
- max_index = max_index < parse_value ? parse_value : max_index;
477
- }
478
-
479
- if (max_index < (2 * variant->map ().size ())) {
480
- Variant array_result (
481
- std::vector<Variant>(max_index + 1 , Variant::Null ()));
482
- for (int i = 0 ; i <= max_index; ++i) {
483
- std::stringstream ss;
484
- ss << i;
485
- auto it_child = variant->map ().find (ss.str ());
486
- if (it_child != variant->map ().end ()) {
487
- array_result.vector ()[i] = it_child->second ;
488
- }
487
+ int64_t max_index = -1 ;
488
+ if (CanConvertVariantMapToVector (*variant, &max_index)) {
489
+ Variant array_result (std::vector<Variant>(max_index + 1 , Variant::Null ()));
490
+ for (int i = 0 ; i <= max_index; ++i) {
491
+ std::stringstream ss;
492
+ ss << i;
493
+ auto it_child = variant->map ().find (ss.str ());
494
+ if (it_child != variant->map ().end ()) {
495
+ array_result.vector ()[i] = it_child->second ;
489
496
}
490
- *variant = array_result;
491
497
}
498
+ *variant = array_result;
492
499
}
493
500
}
494
501
@@ -828,13 +835,26 @@ UtilLeafType GetLeafType(Variant::Type type) {
828
835
// Store the pointers to the key and the value Variant in a map for sorting
829
836
typedef std::pair<const Variant*, const Variant*> NodeSortingData;
830
837
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 ();
844
+ }
845
+
831
846
// Private function to serialize all child nodes
832
847
void ProcessChildNodes (std::stringstream* ss,
833
- std::vector<NodeSortingData>* nodes, bool saw_priority) {
834
- // If any node has priority, sort the vector
848
+ std::vector<NodeSortingData>* nodes, bool saw_priority,
849
+ bool can_convert_vector) {
850
+ // If any node has priority, sort using priority.
835
851
if (saw_priority) {
836
852
QueryParams params;
853
+ assert (params.order_by == QueryParams::kOrderByPriority );
837
854
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);
838
858
}
839
859
840
860
// Serialize each child with its key and its hashed value
@@ -854,23 +874,30 @@ void AppendHashRepAsContainer(std::stringstream* ss, const Variant& data) {
854
874
std::vector<NodeSortingData> nodes;
855
875
856
876
if (data.is_vector ()) {
857
- // Convert vector into map before process it. The map use index string as
858
- // the key.
859
- Variant map = Variant::EmptyMap ();
877
+ // Store index as string to be used for hash calculating, since
878
+ // NodeSortingData stores the pointer to the Variant.
879
+ // This is to avoid making copies of Variant from data.
880
+ std::vector<Variant> index_variants;
881
+ index_variants.reserve (data.vector ().size ());
882
+ bool saw_priority = false ;
860
883
for (int i = 0 ; i < data.vector ().size (); ++i) {
861
884
std::stringstream index_stream;
862
885
index_stream << i;
863
- map.map ()[index_stream.str ()] = data.vector ()[i];
886
+ index_variants.push_back (index_stream.str ());
887
+ nodes.push_back (NodeSortingData (&index_variants[i], &data.vector ()[i]));
888
+ saw_priority =
889
+ saw_priority || !GetVariantPriority (data.vector ()[i]).is_null ();
864
890
}
865
- AppendHashRepAsContainer (ss, map );
891
+ ProcessChildNodes (ss, &nodes, saw_priority, true );
866
892
} else if (data.is_map ()) {
867
893
bool saw_priority = false ;
868
894
for (auto & it_child : data.map ()) {
869
895
nodes.push_back (NodeSortingData (&it_child.first , &it_child.second ));
870
896
saw_priority =
871
897
saw_priority || !GetVariantPriority (it_child.second ).is_null ();
872
898
}
873
- ProcessChildNodes (ss, &nodes, saw_priority);
899
+ bool can_convert_vector = CanConvertVariantMapToVector (data, nullptr );
900
+ ProcessChildNodes (ss, &nodes, saw_priority, can_convert_vector);
874
901
}
875
902
}
876
903
0 commit comments