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+
27+ // Type aliases to reduce complexity
28+ type HashIndex = HashMap < String , usize > ;
29+ type CacheEntry = ( HashIndex , u32 ) ;
30+ type HashIndexCache = HashMap < usize , CacheEntry > ;
31+
32+ static HASH_INDEX_CACHE : LazyLock < Mutex < HashIndexCache > > =
33+ LazyLock :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
1934
2035use super :: {
2136 object:: Pair ,
@@ -1155,6 +1170,11 @@ impl Value {
11551170 self . get_key_value ( key) . map ( |( _, v) | v)
11561171 }
11571172
1173+ #[ inline]
1174+ pub ( crate ) fn get_key_optimized ( & self , key : & str ) -> Option < & Self > {
1175+ self . get_key_value_optimized ( key) . map ( |( _, v) | v)
1176+ }
1177+
11581178 pub ( crate ) fn get_key_value ( & self , key : & str ) -> Option < ( & str , & Self ) > {
11591179 debug_assert ! ( self . is_object( ) ) ;
11601180 let ref_inner = self . as_ref2 ( ) ;
@@ -1173,6 +1193,217 @@ impl Value {
11731193 None
11741194 }
11751195
1196+ /// Optimized key-value lookup with multi-level adaptive strategies
1197+ pub ( crate ) fn get_key_value_optimized ( & self , key : & str ) -> Option < ( & str , & Self ) > {
1198+ debug_assert ! ( self . is_object( ) ) ;
1199+ let ref_inner = self . as_ref2 ( ) ;
1200+
1201+ if let ValueRefInner :: Object ( pairs) = ref_inner {
1202+ let len = pairs. len ( ) ;
1203+
1204+ // Multi-level adaptive optimization strategy
1205+ match len {
1206+ 0 => None ,
1207+ 1 ..=7 => {
1208+ // Small objects: Optimized linear search
1209+ self . linear_search_small ( key, pairs)
1210+ }
1211+ 8 ..=31 => {
1212+ // Medium objects: SIMD-accelerated linear search
1213+ self . simd_search_optimized ( key, pairs)
1214+ }
1215+ _ => {
1216+ // Large objects: Hash index + cache
1217+ self . large_object_search_with_hash ( key, pairs)
1218+ }
1219+ }
1220+ } else if let ValueRefInner :: ObjectOwned ( kv) = ref_inner {
1221+ // For owned objects, use the existing hash map lookup
1222+ if let Some ( ( k, v) ) = kv. get_key_value ( key) {
1223+ return Some ( ( k. as_str ( ) , v) ) ;
1224+ }
1225+ None
1226+ } else {
1227+ None
1228+ }
1229+ }
1230+
1231+ /// Hash index search for large objects (> 32 keys)
1232+ fn large_object_search_with_hash < ' a > (
1233+ & self ,
1234+ key : & str ,
1235+ pairs : & ' a [ ( Value , Value ) ] ,
1236+ ) -> Option < ( & ' a str , & ' a Self ) > {
1237+ let pairs_ptr = pairs. as_ptr ( ) as usize ;
1238+
1239+ // Try to get or build hash index
1240+ if let Ok ( mut cache) = HASH_INDEX_CACHE . lock ( ) {
1241+ let entry = cache. entry ( pairs_ptr) . or_insert_with ( || {
1242+ // Build hash index for this object
1243+ let mut hash_index = HashMap :: with_capacity ( pairs. len ( ) ) ;
1244+ for ( i, ( k, _) ) in pairs. iter ( ) . enumerate ( ) {
1245+ if let Some ( k_str) = k. as_str ( ) {
1246+ // For duplicate keys, keep the first occurrence (consistent with linear search)
1247+ hash_index. entry ( k_str. to_string ( ) ) . or_insert ( i) ;
1248+ }
1249+ }
1250+ ( hash_index, 1 ) // (hash_index, access_count)
1251+ } ) ;
1252+
1253+ // Increment access count
1254+ entry. 1 += 1 ;
1255+
1256+ // Use hash index for lookup
1257+ if let Some ( & index) = entry. 0 . get ( key) {
1258+ if index < pairs. len ( ) {
1259+ if let Some ( k_str) = pairs[ index] . 0 . as_str ( ) {
1260+ if k_str == key {
1261+ return Some ( ( k_str, & pairs[ index] . 1 ) ) ;
1262+ }
1263+ }
1264+ }
1265+ }
1266+
1267+ // Clean up cache if it gets too large (simple LRU-like cleanup)
1268+ if cache. len ( ) > 100 {
1269+ cache. retain ( |_, ( _, access_count) | * access_count > 1 ) ;
1270+ for ( _, access_count) in cache. values_mut ( ) {
1271+ * access_count = ( * access_count) . saturating_sub ( 1 ) ;
1272+ }
1273+ }
1274+ }
1275+
1276+ // Fallback to SIMD search if hash index fails
1277+ self . simd_search_optimized ( key, pairs)
1278+ }
1279+
1280+ /// Optimized linear search for small objects
1281+ #[ inline]
1282+ fn linear_search_small < ' a > (
1283+ & self ,
1284+ key : & str ,
1285+ pairs : & ' a [ ( Value , Value ) ] ,
1286+ ) -> Option < ( & ' a str , & ' a Self ) > {
1287+ let key_len = key. len ( ) ;
1288+
1289+ // Length pre-check optimization for small objects
1290+ for ( k, v) in pairs {
1291+ if let Some ( k_str) = k. as_str ( ) {
1292+ // Length pre-check before string comparison
1293+ if k_str. len ( ) == key_len && k_str == key {
1294+ return Some ( ( k_str, v) ) ;
1295+ }
1296+ }
1297+ }
1298+ None
1299+ }
1300+
1301+ /// SIMD-accelerated search for medium and large objects
1302+ #[ inline]
1303+ fn simd_search_optimized < ' a > (
1304+ & self ,
1305+ key : & str ,
1306+ pairs : & ' a [ ( Value , Value ) ] ,
1307+ ) -> Option < ( & ' a str , & ' a Self ) > {
1308+ let key_bytes = key. as_bytes ( ) ;
1309+
1310+ // Try SIMD optimization for longer keys
1311+ if key_bytes. len ( ) >= 16 {
1312+ if let Some ( result) = self . simd_string_compare ( key, pairs) {
1313+ return Some ( result) ;
1314+ }
1315+ }
1316+
1317+ // Fallback to optimized linear search
1318+ self . linear_search_optimized ( key, pairs)
1319+ }
1320+
1321+ /// SIMD string comparison for keys >= 16 bytes
1322+ #[ cfg( target_arch = "x86_64" ) ]
1323+ fn simd_string_compare < ' a > (
1324+ & self ,
1325+ key : & str ,
1326+ pairs : & ' a [ ( Value , Value ) ] ,
1327+ ) -> Option < ( & ' a str , & ' a Self ) > {
1328+ if !is_x86_feature_detected ! ( "sse2" ) {
1329+ return None ;
1330+ }
1331+
1332+ let key_bytes = key. as_bytes ( ) ;
1333+ let key_len = key_bytes. len ( ) ;
1334+
1335+ unsafe {
1336+ // Load first 16 bytes of key for SIMD comparison
1337+ let key_vec = if key_len >= 16 {
1338+ _mm_loadu_si128 ( key_bytes. as_ptr ( ) as * const __m128i )
1339+ } else {
1340+ // Pad with zeros for shorter keys
1341+ let mut padded = [ 0u8 ; 16 ] ;
1342+ padded[ ..key_len] . copy_from_slice ( key_bytes) ;
1343+ _mm_loadu_si128 ( padded. as_ptr ( ) as * const __m128i )
1344+ } ;
1345+
1346+ for ( k, v) in pairs {
1347+ if let Some ( k_str) = k. as_str ( ) {
1348+ let k_bytes = k_str. as_bytes ( ) ;
1349+
1350+ // Quick length check
1351+ if k_bytes. len ( ) != key_len {
1352+ continue ;
1353+ }
1354+
1355+ if k_bytes. len ( ) >= 16 {
1356+ // SIMD comparison for first 16 bytes
1357+ let k_vec = _mm_loadu_si128 ( k_bytes. as_ptr ( ) as * const __m128i ) ;
1358+ let cmp = _mm_cmpeq_epi8 ( key_vec, k_vec) ;
1359+ let mask = _mm_movemask_epi8 ( cmp) ;
1360+
1361+ if mask == 0xFFFF {
1362+ // First 16 bytes match, check remaining bytes
1363+ if key_len <= 16 || key_bytes[ 16 ..] == k_bytes[ 16 ..] {
1364+ return Some ( ( k_str, v) ) ;
1365+ }
1366+ }
1367+ } else if key_bytes == k_bytes {
1368+ return Some ( ( k_str, v) ) ;
1369+ }
1370+ }
1371+ }
1372+ }
1373+
1374+ None
1375+ }
1376+
1377+ /// Fallback SIMD implementation for non-x86_64 architectures
1378+ #[ cfg( not( target_arch = "x86_64" ) ) ]
1379+ fn simd_string_compare < ' a > (
1380+ & self ,
1381+ _key : & str ,
1382+ _pairs : & ' a [ ( Value , Value ) ] ,
1383+ ) -> Option < ( & ' a str , & ' a Self ) > {
1384+ None
1385+ }
1386+
1387+ /// Optimized linear search with length pre-check
1388+ #[ inline]
1389+ fn linear_search_optimized < ' a > (
1390+ & self ,
1391+ key : & str ,
1392+ pairs : & ' a [ ( Value , Value ) ] ,
1393+ ) -> Option < ( & ' a str , & ' a Self ) > {
1394+ let key_len = key. len ( ) ;
1395+
1396+ for ( k, v) in pairs {
1397+ if let Some ( k_str) = k. as_str ( ) {
1398+ // Length pre-check before string comparison
1399+ if k_str. len ( ) == key_len && k_str == key {
1400+ return Some ( ( k_str, v) ) ;
1401+ }
1402+ }
1403+ }
1404+ None
1405+ }
1406+
11761407 #[ inline]
11771408 pub ( crate ) fn get_key_mut ( & mut self , key : & str ) -> Option < & mut Self > {
11781409 if let ValueMut :: Object ( kv) = self . as_mut ( ) {
0 commit comments