Alternative to Arc<Cow<'static, str>>?

Hello,

I have some data structures that use a lot of Strings, some of which will originate from constants, while others will be based on input, and both are used interchangeably. So I decided to use Cow<'static, str>.

But also, the strings will typically be referred to from multiple places, so I decided to wrap it in an Arc.

But the resulting Arc<Cow<'static, str>> appears wasteful, because if the string is originally a &'static str, it can be shared for free, and reference counting is unnecessary.

Is there a better alternative to Arc<Cow<'static, str>>? Thanks!

arcstr seems to fit.

A better reference-counted string type, with zero-cost (allocation-free) support for string literals, and reference counted substrings

1 Like

There's no shame in writing your own enum, or perhaps Either<&'static str, Arc<str>>, but arcstr might be better optimized if you don't mind the dependency.

3 Likes

arcstr is what I have used, but you may also be interested in atomicow::CowArc, which

  • works for other types than str,
  • is a enum with public structure like Cow[1], and
  • supports borrowed values like Cow.

Either arcstr or atomicow is likely a better choice than your Arc<Cow<'static, str>>, because they don’t require following two pointers to get to the text of the string.


  1. which might be better or worse — it allows explicit construction and pattern matching, but also lets you accidentally depend on the distinct representation of two equal values ↩︎

Since your str is behind an Arc, it is immutable. So I wonder, why bother with owned strings at all? Why don't you use interning? This way all your strings would be allocated from an arena with lifetime 'a, and you could just deal with &'a str everywhere. This would also make your type Copy, which is nice in regards to both ergonomics and performance.

1 Like

That does sound attractive. The possibility of more than one arena existing would make it pretty hairy, though, maybe I can ensure there is only one? The 'a would be everywhere, which feels cumbersome, maybe there should be one and only one arena that is 'static'?

Sure, you can always leak your arena (either it provides that API directly, or you can Box::leak(Box::new(arena)) if it doesn't. That's OK if your strings are really intended to live for the entirety of the program, rather than some more limited scope. You could also just leak strings allocated with the standard global allocator. It will have some overhead (per-allocation header, alignment, and possible memory fragmentation), but depending on your workload it can be entirely insignificant.

If you want an arena that "leaks" strings:

1 Like