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