ulong这是我写线程安全类的第一次真正的冒险。考虑到上面的注释,我是否以一种可能违反我的线程安全声明的方式搞砸了任何事情,或者我正在执行任何没有必要的操作?
public sealed class BitVector : IEnumerable<bool>
{
private readonly long[] m_bits;
private readonly bool m_isThreadSafe;
private readonly ulong m_length;
private long m_version = 0L;
public bool this[long index] {
get {
return this[checked((ulong)index)];
}
set {
this[checked((ulong)index)] = value;
}
}
[CLSCompliant(false)]
public bool this[ulong index] {
get {
if (m_length > index) {
if (m_isThreadSafe) {
return BTConcurrent.AtomicRead(ref m_bits[(index / 64UL)]).IsBitSet(checked((int)index.Mod64()));
}
else {
return m_bits[(index / 64UL)].IsBitSet(checked((int)index.Mod64()));
}
}
else {
throw new ArgumentOutOfRangeException(paramName: nameof(index));
}
}
set {
if (m_length > index) {
if (value) {
if (m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref m_version); }
BTConcurrent.AtomicSetBit(ref m_bits[unchecked(index / 64UL)], checked((int)index.Mod64()));
}
else {
m_bits[unchecked(index / 64UL)].SetBit(checked((int)index.Mod64()));
}
}
else {
if (m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref m_version); }
BTConcurrent.AtomicClearBit(ref m_bits[unchecked(index / 64UL)], checked((int)index.Mod64()));
}
else {
m_bits[unchecked(index / 64UL)].ClearBit(checked((int)index.Mod64()));
}
}
}
else {
throw new ArgumentOutOfRangeException(paramName: nameof(index));
}
}
}
public long Length {
get {
return checked((long)UnsignedLength);
}
}
[CLSCompliant(false)]
public ulong UnsignedLength {
get {
return m_length;
}
}
[CLSCompliant(false)]
public BitVector(ulong length, long initBitPattern, bool isThreadSafe) {
m_bits = new long[((length / 64UL) + Convert.ToUInt64(length.Mod64().IsPositive()))];
m_isThreadSafe = isThreadSafe;
m_length = length;
if (initBitPattern != 0L) {
SetAll(initBitPattern);
}
}
[CLSCompliant(false)]
public BitVector(ulong length, bool isThreadSafe) : this(length, 0L, isThreadSafe) { }
[CLSCompliant(false)]
public BitVector(ulong length) : this(length, false) { }
[CLSCompliant(false)]
public void And(long bitPattern, ulong count) {
And(this, bitPattern, count);
}
public void AndAll(long bitPattern) {
And(bitPattern, unchecked((ulong)m_bits.LongLength));
}
[CLSCompliant(false)]
public void Clear(ulong count) {
SetAll(0L, count);
}
public void ClearAll() {
SetAll(0L, unchecked((ulong)m_bits.LongLength));
}
public IEnumerator<bool> GetEnumerator() {
if (m_isThreadSafe) {
var versionSnapshot = BTConcurrent.AtomicRead(ref m_version);
for (var i = 0UL; i < UnsignedLength; i++) {
if (versionSnapshot == BTConcurrent.AtomicRead(ref m_version)) {
yield return this[i];
}
else {
throw new InvalidOperationException(message: "data was mutated during enumeration, unable to continue");
}
}
}
else {
for (var i = 0UL; i < UnsignedLength; i++) {
yield return this[i];
}
}
}
[CLSCompliant(false)]
public void Or(long bitPattern, ulong count) {
Or(this, bitPattern, count);
}
public void OrAll(long bitPattern) {
Or(bitPattern, unchecked((ulong)m_bits.LongLength));
}
[CLSCompliant(false)]
public void Not(long bitPattern, ulong count) {
Not(this, bitPattern, count);
}
public void NotAll(long bitPattern) {
Not(bitPattern, unchecked((ulong)m_bits.LongLength));
}
[CLSCompliant(false)]
public void SetAll(long bitPattern, ulong count) {
Set(this, bitPattern, count);
}
public void SetAll(long bitPattern) {
SetAll(bitPattern, ((ulong)m_bits.LongLength));
}
public void SetAll() {
SetAll(-1L);
}
public void SetEven() {
OrAll(6148914691236517205L /* equivalent to 1010....1010 */);
}
public void SetOdd() {
OrAll(-6148914691236517206L /* equivalent to 0101....0101 */);
}
[CLSCompliant(false)]
public void Xor(long bitPattern, ulong count) {
Xor(this, bitPattern, count);
}
public void XorAll(long bitPattern) {
Xor(bitPattern, ((ulong)m_bits.LongLength));
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return GetEnumerator();
}
private static void And(BitVector bitVector, long bitPattern, ulong count) {
if (count > unchecked((ulong)bitVector.m_bits.Length)) {
throw new ArgumentOutOfRangeException(paramName: nameof(count));
}
if (bitVector.m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }
for (var i = 0UL; i < count; i++) {
BTConcurrent.AtomicAndAssign(ref bitVector.m_bits[i], bitPattern);
}
}
else {
for (var i = 0UL; i < count; i++) {
bitVector.m_bits[i] &= bitPattern;
}
}
}
private static void Not(BitVector bitVector, long bitPattern, ulong count) {
if (count > unchecked((ulong)bitVector.m_bits.Length)) {
throw new ArgumentOutOfRangeException(paramName: nameof(count));
}
if (bitVector.m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }
for (var i = 0UL; i < count; i++) {
BTConcurrent.AtomicNotAssign(ref bitVector.m_bits[i]);
}
}
else {
for (var i = 0UL; i < count; i++) {
bitVector.m_bits[i] = (~bitPattern);
}
}
}
private static void Or(BitVector bitVector, long bitPattern, ulong count) {
if (count > unchecked((ulong)bitVector.m_bits.Length)) {
throw new ArgumentOutOfRangeException(paramName: nameof(count));
}
if (bitVector.m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }
for (var i = 0UL; i < count; i++) {
BTConcurrent.AtomicOrAssign(ref bitVector.m_bits[i], bitPattern);
}
}
else {
for (var i = 0UL; i < count; i++) {
bitVector.m_bits[i] |= bitPattern;
}
}
}
private static void Set(BitVector bitVector, long bitPattern, ulong count) {
if (count > unchecked((ulong)bitVector.m_bits.Length)) {
throw new ArgumentOutOfRangeException(paramName: nameof(count));
}
if (bitVector.m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }
for (var i = 0UL; i < count; i++) {
BTConcurrent.AtomicWrite(ref bitVector.m_bits[i], bitPattern);
}
}
else {
for (var i = 0UL; i < count; i++) {
bitVector.m_bits[i] = bitPattern;
}
}
}
private static void Xor(BitVector bitVector, long bitPattern, ulong count) {
if (count > unchecked((ulong)bitVector.m_bits.Length)) {
throw new ArgumentOutOfRangeException(paramName: nameof(count));
}
if (bitVector.m_isThreadSafe) {
unchecked { BTConcurrent.AtomicIncrement(ref bitVector.m_version); }
for (var i = 0UL; i < count; i++) {
BTConcurrent.AtomicXorAssign(ref bitVector.m_bits[i], bitPattern);
}
}
else {
for (var i = 0UL; i < count; i++) {
bitVector.m_bits[i] ^= bitPattern;
}
}
}
}发布于 2017-08-08 05:22:59
您不需要在未经检查的上下文中执行像index / 64UL (其中索引是ulong)这样的分区,因为在这种情况下不会发生溢出。另外,您也不需要UL后缀用于64。
您确定需要像long和ulong这样的索引器参数的“大”类型吗?我只会使用int和uint,因为它已经足够了。
在CLS兼容的索引器版本中,您应该检查参数是否为负数,并将其转换为ulong,而无需选中上下文:
public bool this[long index]
{
get
{
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index), index, "Index is negative.");
return this[(ulong)index];
}
set
{
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index), index, "Index is negative.");
this[(ulong)index] = value;
}
}将打开的花括号放置在新行上:)
https://codereview.stackexchange.com/questions/172302
复制相似问题