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