@@ -333,6 +333,15 @@ struct ArcInner<T: ?Sized> {
333
333
data : T ,
334
334
}
335
335
336
+ /// Calculate layout for `ArcInner<T>` using the inner value's layout
337
+ fn arcinner_layout_for_value_layout ( layout : Layout ) -> Layout {
338
+ // Calculate layout using the given value layout.
339
+ // Previously, layout was calculated on the expression
340
+ // `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
341
+ // reference (see #54908).
342
+ Layout :: new :: < ArcInner < ( ) > > ( ) . extend ( layout) . unwrap ( ) . 0 . pad_to_align ( )
343
+ }
344
+
336
345
unsafe impl < T : ?Sized + Sync + Send > Send for ArcInner < T > { }
337
346
unsafe impl < T : ?Sized + Sync + Send > Sync for ArcInner < T > { }
338
347
@@ -1154,11 +1163,7 @@ impl<T: ?Sized> Arc<T> {
1154
1163
allocate : impl FnOnce ( Layout ) -> Result < NonNull < [ u8 ] > , AllocError > ,
1155
1164
mem_to_arcinner : impl FnOnce ( * mut u8 ) -> * mut ArcInner < T > ,
1156
1165
) -> * mut ArcInner < T > {
1157
- // Calculate layout using the given value layout.
1158
- // Previously, layout was calculated on the expression
1159
- // `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
1160
- // reference (see #54908).
1161
- let layout = Layout :: new :: < ArcInner < ( ) > > ( ) . extend ( value_layout) . unwrap ( ) . 0 . pad_to_align ( ) ;
1166
+ let layout = arcinner_layout_for_value_layout ( value_layout) ;
1162
1167
unsafe {
1163
1168
Arc :: try_allocate_for_layout ( value_layout, allocate, mem_to_arcinner)
1164
1169
. unwrap_or_else ( |_| handle_alloc_error ( layout) )
@@ -1176,11 +1181,7 @@ impl<T: ?Sized> Arc<T> {
1176
1181
allocate : impl FnOnce ( Layout ) -> Result < NonNull < [ u8 ] > , AllocError > ,
1177
1182
mem_to_arcinner : impl FnOnce ( * mut u8 ) -> * mut ArcInner < T > ,
1178
1183
) -> Result < * mut ArcInner < T > , AllocError > {
1179
- // Calculate layout using the given value layout.
1180
- // Previously, layout was calculated on the expression
1181
- // `&*(ptr as *const ArcInner<T>)`, but this created a misaligned
1182
- // reference (see #54908).
1183
- let layout = Layout :: new :: < ArcInner < ( ) > > ( ) . extend ( value_layout) . unwrap ( ) . 0 . pad_to_align ( ) ;
1184
+ let layout = arcinner_layout_for_value_layout ( value_layout) ;
1184
1185
1185
1186
let ptr = allocate ( layout) ?;
1186
1187
@@ -1246,7 +1247,7 @@ impl<T> Arc<[T]> {
1246
1247
}
1247
1248
}
1248
1249
1249
- /// Copy elements from slice into newly allocated Arc<\[T\]>
1250
+ /// Copy elements from slice into newly allocated ` Arc<[T]>`
1250
1251
///
1251
1252
/// Unsafe because the caller must either take ownership or bind `T: Copy`.
1252
1253
#[ cfg( not( no_global_oom_handling) ) ]
@@ -1260,6 +1261,49 @@ impl<T> Arc<[T]> {
1260
1261
}
1261
1262
}
1262
1263
1264
+ /// Create an `Arc<[T]>` by reusing the underlying memory
1265
+ /// of a `Vec<T>`. This will return the vector if the existing allocation
1266
+ /// is not large enough.
1267
+ #[ cfg( not( no_global_oom_handling) ) ]
1268
+ fn try_from_vec_in_place ( mut v : Vec < T > ) -> Result < Arc < [ T ] > , Vec < T > > {
1269
+ let layout_elements = Layout :: array :: < T > ( v. len ( ) ) . unwrap ( ) ;
1270
+ let layout_allocation = Layout :: array :: < T > ( v. capacity ( ) ) . unwrap ( ) ;
1271
+ let layout_arcinner = arcinner_layout_for_value_layout ( layout_elements) ;
1272
+ let mut ptr = NonNull :: new ( v. as_mut_ptr ( ) ) . expect ( "`Vec<T>` stores `NonNull<T>`" ) ;
1273
+ if layout_arcinner. size ( ) > layout_allocation. size ( )
1274
+ || layout_arcinner. align ( ) > layout_allocation. align ( )
1275
+ {
1276
+ // Can't fit - calling `grow` would involve `realloc`
1277
+ // (which copies the elements), followed by copying again.
1278
+ return Err ( v) ;
1279
+ }
1280
+ if layout_arcinner. size ( ) < layout_allocation. size ( )
1281
+ || layout_arcinner. align ( ) < layout_allocation. align ( )
1282
+ {
1283
+ // We need to shrink the allocation so that it fits
1284
+ // https://doc.rust-lang.org/nightly/std/alloc/trait.Allocator.html#memory-fitting
1285
+ // SAFETY:
1286
+ // - Vec allocates by requesting `Layout::array::<T>(capacity)`, so this capacity matches
1287
+ // - `layout_arcinner` is smaller
1288
+ // If this fails, the ownership has not been transferred
1289
+ if let Ok ( p) = unsafe { Global . shrink ( ptr. cast ( ) , layout_allocation, layout_arcinner) }
1290
+ {
1291
+ ptr = p. cast ( ) ;
1292
+ } else {
1293
+ return Err ( v) ;
1294
+ }
1295
+ }
1296
+ // Make sure the vec's memory isn't deallocated now
1297
+ let v = mem:: ManuallyDrop :: new ( v) ;
1298
+ let ptr: * mut ArcInner < [ T ] > = ptr:: slice_from_raw_parts_mut ( ptr. as_ptr ( ) , v. len ( ) ) as _ ;
1299
+ unsafe {
1300
+ ptr:: copy ( ptr. cast :: < T > ( ) , & mut ( * ptr) . data as * mut [ T ] as * mut T , v. len ( ) ) ;
1301
+ ptr:: write ( & mut ( * ptr) . strong , atomic:: AtomicUsize :: new ( 1 ) ) ;
1302
+ ptr:: write ( & mut ( * ptr) . weak , atomic:: AtomicUsize :: new ( 1 ) ) ;
1303
+ Ok ( Self :: from_ptr ( ptr) )
1304
+ }
1305
+ }
1306
+
1263
1307
/// Constructs an `Arc<[T]>` from an iterator known to be of a certain size.
1264
1308
///
1265
1309
/// Behavior is undefined should the size be wrong.
@@ -2571,14 +2615,17 @@ impl<T> From<Vec<T>> for Arc<[T]> {
2571
2615
/// assert_eq!(&[1, 2, 3], &shared[..]);
2572
2616
/// ```
2573
2617
#[ inline]
2574
- fn from ( mut v : Vec < T > ) -> Arc < [ T ] > {
2575
- unsafe {
2576
- let arc = Arc :: copy_from_slice ( & v) ;
2577
-
2578
- // Allow the Vec to free its memory, but not destroy its contents
2579
- v. set_len ( 0 ) ;
2580
-
2581
- arc
2618
+ fn from ( v : Vec < T > ) -> Arc < [ T ] > {
2619
+ match Arc :: try_from_vec_in_place ( v) {
2620
+ Ok ( rc) => rc,
2621
+ Err ( mut v) => {
2622
+ unsafe {
2623
+ let rc = Arc :: copy_from_slice ( & v) ;
2624
+ // Allow the Vec to free its memory, but not destroy its contents
2625
+ v. set_len ( 0 ) ;
2626
+ rc
2627
+ }
2628
+ }
2582
2629
}
2583
2630
}
2584
2631
}
0 commit comments