11use core:: mem:: size_of;
2- #[ cfg( feature = "sort_keys" ) ]
3- use std:: collections:: BTreeMap ;
42use std:: {
53 alloc:: Layout ,
4+ collections:: HashMap ,
65 fmt:: { Debug , Display , Formatter } ,
76 mem:: { transmute, ManuallyDrop } ,
87 ptr:: NonNull ,
98 slice:: from_raw_parts,
109 str:: from_utf8_unchecked,
11- sync:: Arc ,
10+ sync:: { Arc , Mutex } ,
1211} ;
1312
1413#[ cfg( not( feature = "sort_keys" ) ) ]
1514use ahash:: AHashMap ;
1615use faststr:: FastStr ;
1716use ref_cast:: RefCast ;
1817use serde:: ser:: { Serialize , SerializeMap , SerializeSeq } ;
18+ #[ cfg( feature = "sort_keys" ) ]
19+ use std:: collections:: BTreeMap ;
20+
21+ #[ cfg( target_arch = "x86_64" ) ]
22+ use std:: arch:: x86_64:: * ;
23+
24+ /// Hash index cache for large objects
25+ use std:: sync:: LazyLock ;
26+ static HASH_INDEX_CACHE : LazyLock < Mutex < HashMap < usize , ( HashMap < String , usize > , u32 ) > > > =
27+ LazyLock :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
1928
2029use super :: {
2130 object:: Pair ,
@@ -1155,6 +1164,11 @@ impl Value {
11551164 self . get_key_value ( key) . map ( |( _, v) | v)
11561165 }
11571166
1167+ #[ inline]
1168+ pub ( crate ) fn get_key_optimized ( & self , key : & str ) -> Option < & Self > {
1169+ self . get_key_value_optimized ( key) . map ( |( _, v) | v)
1170+ }
1171+
11581172 pub ( crate ) fn get_key_value ( & self , key : & str ) -> Option < ( & str , & Self ) > {
11591173 debug_assert ! ( self . is_object( ) ) ;
11601174 let ref_inner = self . as_ref2 ( ) ;
@@ -1173,6 +1187,217 @@ impl Value {
11731187 None
11741188 }
11751189
1190+ /// Optimized key-value lookup with multi-level adaptive strategies
1191+ pub ( crate ) fn get_key_value_optimized ( & self , key : & str ) -> Option < ( & str , & Self ) > {
1192+ debug_assert ! ( self . is_object( ) ) ;
1193+ let ref_inner = self . as_ref2 ( ) ;
1194+
1195+ if let ValueRefInner :: Object ( pairs) = ref_inner {
1196+ let len = pairs. len ( ) ;
1197+
1198+ // Multi-level adaptive optimization strategy
1199+ match len {
1200+ 0 => None ,
1201+ 1 ..=7 => {
1202+ // Small objects: Optimized linear search
1203+ self . linear_search_small ( key, pairs)
1204+ }
1205+ 8 ..=31 => {
1206+ // Medium objects: SIMD-accelerated linear search
1207+ self . simd_search_optimized ( key, pairs)
1208+ }
1209+ _ => {
1210+ // Large objects: Hash index + cache
1211+ self . large_object_search_with_hash ( key, pairs)
1212+ }
1213+ }
1214+ } else if let ValueRefInner :: ObjectOwned ( kv) = ref_inner {
1215+ // For owned objects, use the existing hash map lookup
1216+ if let Some ( ( k, v) ) = kv. get_key_value ( key) {
1217+ return Some ( ( k. as_str ( ) , v) ) ;
1218+ }
1219+ None
1220+ } else {
1221+ None
1222+ }
1223+ }
1224+
1225+ /// Hash index search for large objects (> 32 keys)
1226+ fn large_object_search_with_hash < ' a > (
1227+ & self ,
1228+ key : & str ,
1229+ pairs : & ' a [ ( Value , Value ) ] ,
1230+ ) -> Option < ( & ' a str , & ' a Self ) > {
1231+ let pairs_ptr = pairs. as_ptr ( ) as usize ;
1232+
1233+ // Try to get or build hash index
1234+ if let Ok ( mut cache) = HASH_INDEX_CACHE . lock ( ) {
1235+ let entry = cache. entry ( pairs_ptr) . or_insert_with ( || {
1236+ // Build hash index for this object
1237+ let mut hash_index = HashMap :: with_capacity ( pairs. len ( ) ) ;
1238+ for ( i, ( k, _) ) in pairs. iter ( ) . enumerate ( ) {
1239+ if let Some ( k_str) = k. as_str ( ) {
1240+ // For duplicate keys, keep the first occurrence (consistent with linear search)
1241+ hash_index. entry ( k_str. to_string ( ) ) . or_insert ( i) ;
1242+ }
1243+ }
1244+ ( hash_index, 1 ) // (hash_index, access_count)
1245+ } ) ;
1246+
1247+ // Increment access count
1248+ entry. 1 += 1 ;
1249+
1250+ // Use hash index for lookup
1251+ if let Some ( & index) = entry. 0 . get ( key) {
1252+ if index < pairs. len ( ) {
1253+ if let Some ( k_str) = pairs[ index] . 0 . as_str ( ) {
1254+ if k_str == key {
1255+ return Some ( ( k_str, & pairs[ index] . 1 ) ) ;
1256+ }
1257+ }
1258+ }
1259+ }
1260+
1261+ // Clean up cache if it gets too large (simple LRU-like cleanup)
1262+ if cache. len ( ) > 100 {
1263+ cache. retain ( |_, ( _, access_count) | * access_count > 1 ) ;
1264+ for ( _, access_count) in cache. values_mut ( ) {
1265+ * access_count = ( * access_count) . saturating_sub ( 1 ) ;
1266+ }
1267+ }
1268+ }
1269+
1270+ // Fallback to SIMD search if hash index fails
1271+ self . simd_search_optimized ( key, pairs)
1272+ }
1273+
1274+ /// Optimized linear search for small objects
1275+ #[ inline]
1276+ fn linear_search_small < ' a > (
1277+ & self ,
1278+ key : & str ,
1279+ pairs : & ' a [ ( Value , Value ) ] ,
1280+ ) -> Option < ( & ' a str , & ' a Self ) > {
1281+ let key_len = key. len ( ) ;
1282+
1283+ // Length pre-check optimization for small objects
1284+ for ( k, v) in pairs {
1285+ if let Some ( k_str) = k. as_str ( ) {
1286+ // Length pre-check before string comparison
1287+ if k_str. len ( ) == key_len && k_str == key {
1288+ return Some ( ( k_str, v) ) ;
1289+ }
1290+ }
1291+ }
1292+ None
1293+ }
1294+
1295+ /// SIMD-accelerated search for medium and large objects
1296+ #[ inline]
1297+ fn simd_search_optimized < ' a > (
1298+ & self ,
1299+ key : & str ,
1300+ pairs : & ' a [ ( Value , Value ) ] ,
1301+ ) -> Option < ( & ' a str , & ' a Self ) > {
1302+ let key_bytes = key. as_bytes ( ) ;
1303+
1304+ // Try SIMD optimization for longer keys
1305+ if key_bytes. len ( ) >= 16 {
1306+ if let Some ( result) = self . simd_string_compare ( key, pairs) {
1307+ return Some ( result) ;
1308+ }
1309+ }
1310+
1311+ // Fallback to optimized linear search
1312+ self . linear_search_optimized ( key, pairs)
1313+ }
1314+
1315+ /// SIMD string comparison for keys >= 16 bytes
1316+ #[ cfg( target_arch = "x86_64" ) ]
1317+ fn simd_string_compare < ' a > (
1318+ & self ,
1319+ key : & str ,
1320+ pairs : & ' a [ ( Value , Value ) ] ,
1321+ ) -> Option < ( & ' a str , & ' a Self ) > {
1322+ if !is_x86_feature_detected ! ( "sse2" ) {
1323+ return None ;
1324+ }
1325+
1326+ let key_bytes = key. as_bytes ( ) ;
1327+ let key_len = key_bytes. len ( ) ;
1328+
1329+ unsafe {
1330+ // Load first 16 bytes of key for SIMD comparison
1331+ let key_vec = if key_len >= 16 {
1332+ _mm_loadu_si128 ( key_bytes. as_ptr ( ) as * const __m128i )
1333+ } else {
1334+ // Pad with zeros for shorter keys
1335+ let mut padded = [ 0u8 ; 16 ] ;
1336+ padded[ ..key_len] . copy_from_slice ( key_bytes) ;
1337+ _mm_loadu_si128 ( padded. as_ptr ( ) as * const __m128i )
1338+ } ;
1339+
1340+ for ( k, v) in pairs {
1341+ if let Some ( k_str) = k. as_str ( ) {
1342+ let k_bytes = k_str. as_bytes ( ) ;
1343+
1344+ // Quick length check
1345+ if k_bytes. len ( ) != key_len {
1346+ continue ;
1347+ }
1348+
1349+ if k_bytes. len ( ) >= 16 {
1350+ // SIMD comparison for first 16 bytes
1351+ let k_vec = _mm_loadu_si128 ( k_bytes. as_ptr ( ) as * const __m128i ) ;
1352+ let cmp = _mm_cmpeq_epi8 ( key_vec, k_vec) ;
1353+ let mask = _mm_movemask_epi8 ( cmp) ;
1354+
1355+ if mask == 0xFFFF {
1356+ // First 16 bytes match, check remaining bytes
1357+ if key_len <= 16 || key_bytes[ 16 ..] == k_bytes[ 16 ..] {
1358+ return Some ( ( k_str, v) ) ;
1359+ }
1360+ }
1361+ } else if key_bytes == k_bytes {
1362+ return Some ( ( k_str, v) ) ;
1363+ }
1364+ }
1365+ }
1366+ }
1367+
1368+ None
1369+ }
1370+
1371+ /// Fallback SIMD implementation for non-x86_64 architectures
1372+ #[ cfg( not( target_arch = "x86_64" ) ) ]
1373+ fn simd_string_compare < ' a > (
1374+ & self ,
1375+ _key : & str ,
1376+ _pairs : & ' a [ ( Value , Value ) ] ,
1377+ ) -> Option < ( & ' a str , & ' a Self ) > {
1378+ None
1379+ }
1380+
1381+ /// Optimized linear search with length pre-check
1382+ #[ inline]
1383+ fn linear_search_optimized < ' a > (
1384+ & self ,
1385+ key : & str ,
1386+ pairs : & ' a [ ( Value , Value ) ] ,
1387+ ) -> Option < ( & ' a str , & ' a Self ) > {
1388+ let key_len = key. len ( ) ;
1389+
1390+ for ( k, v) in pairs {
1391+ if let Some ( k_str) = k. as_str ( ) {
1392+ // Length pre-check before string comparison
1393+ if k_str. len ( ) == key_len && k_str == key {
1394+ return Some ( ( k_str, v) ) ;
1395+ }
1396+ }
1397+ }
1398+ None
1399+ }
1400+
11761401 #[ inline]
11771402 pub ( crate ) fn get_key_mut ( & mut self , key : & str ) -> Option < & mut Self > {
11781403 if let ValueMut :: Object ( kv) = self . as_mut ( ) {
0 commit comments