Skip to content

[API Proposal]: Generic Interlocked.Or/And for enums and small numbers #114568

@MihaZupan

Description

@MihaZupan

Background and motivation

#65184 made it possible to simplify code around Exchange/CompareExchange, but when dealing with enums you're still forced to use unsafe casts back and forth.

A few examples: https://grep.app/search?f.repo=dotnet%2Fruntime&regexp=true&q=Interlocked%5C.%28%3F%3AOr%7CAnd%29%5C%28ref+Unsafe%5C.As

API Proposal

namespace System.Threading;

public static class Interlocked
{
    // Existing naming:
    // public static long Or(ref long location1, long value); // and int, uint, ulong
    // public static T Exchange<T>(ref T location1, T value);

    public static T Or<T>(ref T location1, T value) where T : struct;
    public static T And<T>(ref T location1, T value) where T : struct;
}

API Usage

Debug.Assert(sizeof(Flags) == sizeof(ulong));
Interlocked.Or(ref Unsafe.As<Flags, ulong>(ref _flags), (ulong)flags);

becomes

Interlocked.Or(ref _flags, flags); 

Alternative Designs

Exchange/CompareExchange also have overloads for byte/sbyte/ushort/short.
We could list all of them for Or/And as well, with a generic one for enums.

namespace System.Threading;

public static class Interlocked
{
    // int/uint/long/ulong overloads already exist
    public static T Or<T>(ref T location1, T value) where T : struct, Enum;
    public static sbyte Or(ref sbyte location1, sbyte value);
    public static byte Or(ref byte location1, byte value);
    public static short Or(ref short location1, short value);
    public static ushort Or(ref ushort location1, ushort value);

    public static T And<T>(ref T location1, T value) where T : struct, Enum;
    public static sbyte And(ref sbyte location1, sbyte value);
    public static byte And(ref byte location1, byte value);
    public static short And(ref short location1, short value);
    public static ushort And(ref ushort location1, ushort value);

    // Q: Do we need bool? Half of the operations are expensive nops
    // Q: What about nint/nuint? Add/Increment/Decrement don't have those
}

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions