mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-11 04:52:21 +02:00
Experimental bitfields
This commit is contained in:
parent
f37fb2c1b7
commit
9e80281d1a
7 changed files with 416 additions and 26 deletions
279
BeefLibs/corlib/src/Bitfield.bf
Normal file
279
BeefLibs/corlib/src/Bitfield.bf
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace System
|
||||||
|
{
|
||||||
|
[AttributeUsage(.Field | .StaticField)]
|
||||||
|
struct BitfieldAttribute : Attribute, IOnFieldInit
|
||||||
|
{
|
||||||
|
public enum BitSpec
|
||||||
|
{
|
||||||
|
case Auto;
|
||||||
|
case AutoAt(int pos);
|
||||||
|
case AutoRev;
|
||||||
|
case Bits(int bits);
|
||||||
|
case BitsRev(int bits);
|
||||||
|
case BitsAt(int bits, int pos);
|
||||||
|
case BitRange(IndexRange range);
|
||||||
|
case ValueRange(Range range);
|
||||||
|
case ValueRangeRev(Range range);
|
||||||
|
case ValueRangeAt(Range range, int pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ProtectionKind
|
||||||
|
{
|
||||||
|
Private = 0,
|
||||||
|
Public = 1,
|
||||||
|
Protected = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AccessFlags
|
||||||
|
{
|
||||||
|
Read = 1,
|
||||||
|
Write = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String mName;
|
||||||
|
protected int32 mBitPos = -1;
|
||||||
|
protected BitSpec mBitSpec;
|
||||||
|
protected int32 mFieldIdx = 0;
|
||||||
|
protected Type mBFieldType = null;
|
||||||
|
protected ProtectionKind mProtection;
|
||||||
|
protected AccessFlags mAccessFlags;
|
||||||
|
|
||||||
|
public this(ProtectionKind protection, BitSpec bitSpec, String name, AccessFlags accessFlags = .Read | .Write)
|
||||||
|
{
|
||||||
|
mName = name;
|
||||||
|
mBitSpec = bitSpec;
|
||||||
|
mProtection = protection;
|
||||||
|
mAccessFlags = accessFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Comptime]
|
||||||
|
public void OnFieldInit(ComptimeFieldInfo fieldInfo, Self* prev) mut
|
||||||
|
{
|
||||||
|
if (mBFieldType == null)
|
||||||
|
mBFieldType = fieldInfo.FieldType;
|
||||||
|
var buType = mBFieldType;
|
||||||
|
if (buType.IsEnum)
|
||||||
|
buType = buType.UnderlyingType;
|
||||||
|
|
||||||
|
if (buType.IsFloatingPoint)
|
||||||
|
Runtime.FatalError("Invalid bitfield type");
|
||||||
|
|
||||||
|
bool isRev = false;
|
||||||
|
int32 bitCount = 0;
|
||||||
|
int32 underlyingBitCount = fieldInfo.FieldType.Size * 8;
|
||||||
|
|
||||||
|
int32 GetBitSize(int min, int max)
|
||||||
|
{
|
||||||
|
var min;
|
||||||
|
var max;
|
||||||
|
if (min < 0)
|
||||||
|
min = ~min;
|
||||||
|
if (max < 0)
|
||||||
|
max = ~max;
|
||||||
|
uint64 value = (uint64)min | (uint64)max;
|
||||||
|
|
||||||
|
int32 bitCount = 1;
|
||||||
|
if (buType.IsSigned)
|
||||||
|
bitCount++;
|
||||||
|
|
||||||
|
while ((value >>= 1) != 0)
|
||||||
|
bitCount++;
|
||||||
|
|
||||||
|
return bitCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasRange = false;
|
||||||
|
bool rangeCheckMin = false;
|
||||||
|
bool rangeCheckMax = false;
|
||||||
|
int minVal = 0;
|
||||||
|
int maxVal = 0;
|
||||||
|
|
||||||
|
switch (mBitSpec)
|
||||||
|
{
|
||||||
|
case .Bits(let bits):
|
||||||
|
bitCount = (.)bits;
|
||||||
|
case .BitsRev(let bits):
|
||||||
|
bitCount = (.)bits;
|
||||||
|
isRev = true;
|
||||||
|
case .BitsAt(let bits, let pos):
|
||||||
|
bitCount = (.)bits;
|
||||||
|
mBitPos = (.)pos;
|
||||||
|
case .BitRange(let range):
|
||||||
|
bitCount = (.)range.GetLength(underlyingBitCount);
|
||||||
|
mBitPos = (.)range.Start.Get(underlyingBitCount);
|
||||||
|
case .ValueRange(let range):
|
||||||
|
minVal = range.Start;
|
||||||
|
maxVal = range.End - 1;
|
||||||
|
hasRange = true;
|
||||||
|
bitCount = GetBitSize(minVal, maxVal);
|
||||||
|
case .ValueRangeRev(let range):
|
||||||
|
minVal = range.Start;
|
||||||
|
maxVal = range.End - 1;
|
||||||
|
hasRange = true;
|
||||||
|
bitCount = GetBitSize(minVal, maxVal);
|
||||||
|
isRev = true;
|
||||||
|
case .ValueRangeAt(let range, int pos):
|
||||||
|
bitCount = GetBitSize(range.Start, range.End - 1);
|
||||||
|
bitCount = (.)pos;
|
||||||
|
default:
|
||||||
|
Runtime.FatalError("Invalid bitspec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((prev != null) && (prev.mFieldIdx == fieldInfo.FieldIdx))
|
||||||
|
{
|
||||||
|
if (mBitPos == -1)
|
||||||
|
{
|
||||||
|
mBitPos = prev.mBitPos;
|
||||||
|
if (isRev)
|
||||||
|
mBitPos -= bitCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBitPos == -1)
|
||||||
|
mBitPos = isRev ? underlyingBitCount - bitCount : 0;
|
||||||
|
|
||||||
|
if (Compiler.IsBuilding)
|
||||||
|
Debug.WriteLine($"OnFieldInit Name:{mName} BitPos:{mBitPos} BitCount:{bitCount} BuType:{buType}");
|
||||||
|
|
||||||
|
int bitSize = fieldInfo.FieldType.Size * 8;
|
||||||
|
if ((mBitPos < 0) || (mBitPos + bitCount > bitSize))
|
||||||
|
Runtime.FatalError("Bitfield exceeds bounds of underlying value");
|
||||||
|
|
||||||
|
String str = scope .();
|
||||||
|
if (mProtection == .Public)
|
||||||
|
str.Append("public ");
|
||||||
|
else if (mProtection == .Protected)
|
||||||
|
str.Append("protected ");
|
||||||
|
|
||||||
|
void TypeStr(String str, Type t)
|
||||||
|
{
|
||||||
|
if (t.IsPrimitive)
|
||||||
|
t.GetFullName(str);
|
||||||
|
else
|
||||||
|
str.AppendF($"comptype({(int)t.TypeId})");
|
||||||
|
}
|
||||||
|
|
||||||
|
String uTypeStr = TypeStr(.. scope .(), fieldInfo.FieldType);
|
||||||
|
String bTypeStr = TypeStr(.. scope .(), mBFieldType);
|
||||||
|
int mask = ((1 << mBitPos) << bitCount) - (1 << mBitPos);
|
||||||
|
|
||||||
|
if ((!hasRange) && (mBFieldType.IsSigned))
|
||||||
|
{
|
||||||
|
minVal = -(1<<(bitCount-1));
|
||||||
|
maxVal = (1<<(bitCount-1))-1;
|
||||||
|
}
|
||||||
|
else if (!hasRange)
|
||||||
|
{
|
||||||
|
maxVal = (1<<(bitCount))-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
str.AppendF($"{bTypeStr} {mName}\n{{\n");
|
||||||
|
|
||||||
|
if (mAccessFlags.HasFlag(.Read))
|
||||||
|
{
|
||||||
|
str.Append("\t[Inline]\n\tget => ");
|
||||||
|
if (mBFieldType == typeof(bool))
|
||||||
|
str.AppendF($"(({fieldInfo.Name} & {mask}) >> {mBitPos}) != 0;\n");
|
||||||
|
else if (buType.IsSigned)
|
||||||
|
str.AppendF($"(.)((int)((({fieldInfo.Name} & 0x{mask:X}) >> {mBitPos}) ^ 0x{1 << (bitCount - 1):X}) - 0x{1 << (bitCount - 1):X});\n");
|
||||||
|
else
|
||||||
|
str.AppendF($"(.)(({fieldInfo.Name} & 0x{mask:X}) >> {mBitPos});\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBFieldType.IsInteger)
|
||||||
|
{
|
||||||
|
if (mBFieldType.IsSigned)
|
||||||
|
{
|
||||||
|
rangeCheckMin = minVal != -(1<<(mBFieldType.Size*8-1));
|
||||||
|
rangeCheckMax = maxVal != (1<<(mBFieldType.Size*8-1))-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rangeCheckMin = minVal != 0;
|
||||||
|
rangeCheckMax = maxVal != (1<<mBFieldType.Size*8)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAccessFlags.HasFlag(.Write))
|
||||||
|
{
|
||||||
|
for (int pass < 2)
|
||||||
|
{
|
||||||
|
if (!rangeCheckMin && !rangeCheckMax)
|
||||||
|
{
|
||||||
|
if (pass == 0)
|
||||||
|
{
|
||||||
|
str.AppendF($"\t[Inline]\n\tset{(fieldInfo.Owner.IsStruct ? " mut" : "")}\n\t{{\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str.AppendF($"\t[Inline, {((pass == 0) ? "Checked" : "Unchecked")}]\n\tset{(fieldInfo.Owner.IsStruct ? " mut" : "")}\n\t{{\n");
|
||||||
|
if ((pass == 0) && (rangeCheckMin) && (rangeCheckMax))
|
||||||
|
str.AppendF($"\t\tRuntime.Assert((value >= {minVal}) && (value <= {maxVal}));\n");
|
||||||
|
else if ((pass == 0) && (rangeCheckMin))
|
||||||
|
str.AppendF($"\t\tRuntime.Assert(value >= {minVal});\n");
|
||||||
|
else if ((pass == 0) && (rangeCheckMax))
|
||||||
|
str.AppendF($"\t\tRuntime.Assert(value <= {maxVal});\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBFieldType == typeof(bool))
|
||||||
|
str.AppendF($"\t\t{fieldInfo.Name} = ({fieldInfo.Name} & ({uTypeStr})~0x{mask:X}) | (value ? 0x{mask:X} : 0);\n");
|
||||||
|
else
|
||||||
|
str.AppendF($"\t\t{fieldInfo.Name} = ({fieldInfo.Name} & ({uTypeStr})~0x{mask:X}) | ((({uTypeStr})value << {mBitPos}) & ({uTypeStr})0x{mask:X});\n");
|
||||||
|
|
||||||
|
str.Append("\t}\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str.Append("}\n");
|
||||||
|
|
||||||
|
Compiler.EmitTypeBody(fieldInfo.Owner, str);
|
||||||
|
|
||||||
|
if (!isRev)
|
||||||
|
mBitPos += bitCount;
|
||||||
|
mFieldIdx = (.)fieldInfo.FieldIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(.Field | .StaticField)]
|
||||||
|
struct BitfieldAttribute<TField> : BitfieldAttribute
|
||||||
|
{
|
||||||
|
int GetBitCount()
|
||||||
|
{
|
||||||
|
int val = typeof(TField).BitSize;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSpec FixSpec(BitSpec spec)
|
||||||
|
{
|
||||||
|
switch (spec)
|
||||||
|
{
|
||||||
|
case .Auto:
|
||||||
|
return .Bits(typeof(TField).BitSize);
|
||||||
|
case .AutoRev():
|
||||||
|
return .BitsRev(typeof(TField).BitSize);
|
||||||
|
case .AutoAt(let pos):
|
||||||
|
return .BitsAt(typeof(TField).BitSize, pos);
|
||||||
|
default:
|
||||||
|
return spec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(ProtectionKind protection, String name, AccessFlags accessFlags = .Read | .Write) : base(protection, FixSpec(.Auto), name, accessFlags)
|
||||||
|
{
|
||||||
|
/*if (Compiler.IsBuilding)
|
||||||
|
Debug.WriteLine($"typeof.BitSize:{typeof(TField).BitSize} mBitCount:{mBitCount}"); //*/
|
||||||
|
mBFieldType = typeof(TField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public this(ProtectionKind protection, BitSpec bitSpec, String name, AccessFlags accessFlags = .Read | .Write) : base(protection, FixSpec(bitSpec), name, accessFlags)
|
||||||
|
{
|
||||||
|
mBFieldType = typeof(TField);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -216,12 +216,7 @@ namespace System.Collections
|
||||||
[Checked]
|
[Checked]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int idx;
|
int idx = index.Get(mSize);
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case .FromFront(let offset): idx = offset;
|
|
||||||
case .FromEnd(let offset): idx = mSize - offset;
|
|
||||||
}
|
|
||||||
Runtime.Assert((uint)idx < (uint)mSize);
|
Runtime.Assert((uint)idx < (uint)mSize);
|
||||||
return ref mItems[idx];
|
return ref mItems[idx];
|
||||||
}
|
}
|
||||||
|
@ -229,24 +224,13 @@ namespace System.Collections
|
||||||
[Unchecked, Inline]
|
[Unchecked, Inline]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int idx;
|
return ref mItems[index.Get(mSize)];
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case .FromFront(let offset): idx = offset;
|
|
||||||
case .FromEnd(let offset): idx = mSize - offset;
|
|
||||||
}
|
|
||||||
return ref mItems[idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Checked]
|
[Checked]
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
int idx;
|
int idx = index.Get(mSize);
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case .FromFront(let offset): idx = offset;
|
|
||||||
case .FromEnd(let offset): idx = mSize - offset;
|
|
||||||
}
|
|
||||||
Runtime.Assert((uint)idx < (uint)mSize);
|
Runtime.Assert((uint)idx < (uint)mSize);
|
||||||
mItems[idx] = value;
|
mItems[idx] = value;
|
||||||
#if VERSION_LIST
|
#if VERSION_LIST
|
||||||
|
@ -257,13 +241,7 @@ namespace System.Collections
|
||||||
[Unchecked, Inline]
|
[Unchecked, Inline]
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
int idx;
|
mItems[index.Get(mSize)] = value;
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case .FromFront(let offset): idx = offset;
|
|
||||||
case .FromEnd(let offset): idx = mSize - offset;
|
|
||||||
}
|
|
||||||
mItems[idx] = value;
|
|
||||||
#if VERSION_LIST
|
#if VERSION_LIST
|
||||||
mVersion++;
|
mVersion++;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,16 @@ namespace System
|
||||||
offset.ToString(strBuffer);
|
offset.ToString(strBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Inline]
|
||||||
|
public int Get(int size)
|
||||||
|
{
|
||||||
|
switch (this)
|
||||||
|
{
|
||||||
|
case .FromFront(let offset): return offset;
|
||||||
|
case .FromEnd(let offset): return size - offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Range : RangeExpression, IEnumerable<int>
|
struct Range : RangeExpression, IEnumerable<int>
|
||||||
|
@ -310,6 +320,14 @@ namespace System
|
||||||
strBuffer.Append("..<");
|
strBuffer.Append("..<");
|
||||||
mEnd.ToString(strBuffer);
|
mEnd.ToString(strBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetLength(int size)
|
||||||
|
{
|
||||||
|
int length = mEnd.Get(size) - mStart.Get(size);
|
||||||
|
if (mIsClosed)
|
||||||
|
length++;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ClosedRange : RangeExpression, IEnumerable<int>
|
struct ClosedRange : RangeExpression, IEnumerable<int>
|
||||||
|
|
|
@ -2153,6 +2153,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
|
||||||
<ClInclude Include="util\Array.h" />
|
<ClInclude Include="util\Array.h" />
|
||||||
<ClInclude Include="util\BeefPerf.h" />
|
<ClInclude Include="util\BeefPerf.h" />
|
||||||
<ClInclude Include="util\BinaryHeap.h" />
|
<ClInclude Include="util\BinaryHeap.h" />
|
||||||
|
<ClInclude Include="util\BitSet.h" />
|
||||||
<ClInclude Include="util\BSpline.h" />
|
<ClInclude Include="util\BSpline.h" />
|
||||||
<ClInclude Include="util\BumpAllocator.h" />
|
<ClInclude Include="util\BumpAllocator.h" />
|
||||||
<ClInclude Include="util\CatmullRom.h" />
|
<ClInclude Include="util\CatmullRom.h" />
|
||||||
|
|
|
@ -1105,6 +1105,9 @@
|
||||||
<ClInclude Include="util\Compress.h">
|
<ClInclude Include="util\Compress.h">
|
||||||
<Filter>src\util</Filter>
|
<Filter>src\util</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="util\BitSet.h">
|
||||||
|
<Filter>src\util</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
||||||
|
|
61
BeefySysLib/util/BitSet.h
Normal file
61
BeefySysLib/util/BitSet.h
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BFPlatform.h"
|
||||||
|
|
||||||
|
NS_BF_BEGIN;
|
||||||
|
|
||||||
|
#define BF_BITSET_ELEM_SIZE (sizeof(uintptr)*8)
|
||||||
|
|
||||||
|
class BitSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uintptr* mBits;
|
||||||
|
int mNumInts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BitSet()
|
||||||
|
{
|
||||||
|
mNumInts = 0;
|
||||||
|
mBits = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet(int numBits)
|
||||||
|
{
|
||||||
|
mNumInts = 0;
|
||||||
|
mBits = NULL;
|
||||||
|
this->Resize(numBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
~BitSet()
|
||||||
|
{
|
||||||
|
delete this->mBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(int numBits)
|
||||||
|
{
|
||||||
|
int numInts = (numBits + BF_BITSET_ELEM_SIZE - 1) / BF_BITSET_ELEM_SIZE;
|
||||||
|
if (numInts == mNumInts)
|
||||||
|
return;
|
||||||
|
this->mNumInts = numInts;
|
||||||
|
delete this->mBits;
|
||||||
|
this->mBits = new uintptr[numInts];
|
||||||
|
memset(this->mBits, 0, numInts * sizeof(uintptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSet(int idx)
|
||||||
|
{
|
||||||
|
return (this->mBits[idx / BF_BITSET_ELEM_SIZE] & ((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(int idx)
|
||||||
|
{
|
||||||
|
this->mBits[idx / BF_BITSET_ELEM_SIZE] |= ((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear(int idx)
|
||||||
|
{
|
||||||
|
this->mBits[idx / BF_BITSET_ELEM_SIZE] &= ~((uintptr)1 << (idx % BF_BITSET_ELEM_SIZE));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_BF_END;
|
50
IDEHelper/Tests/src/Bitfields.bf
Normal file
50
IDEHelper/Tests/src/Bitfields.bf
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
namespace Tests
|
||||||
|
{
|
||||||
|
class Bitfields
|
||||||
|
{
|
||||||
|
enum EnumA
|
||||||
|
{
|
||||||
|
A = -64,
|
||||||
|
B = 12,
|
||||||
|
C = 63
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StructA
|
||||||
|
{
|
||||||
|
[Bitfield<uint8>(.Public, "A")]
|
||||||
|
[Bitfield<uint8>(.Public, .Bits(3), "B")]
|
||||||
|
[Bitfield<EnumA>(.Public, "C")]
|
||||||
|
[Bitfield(.Public, .ValueRange(0..<12), "D")]
|
||||||
|
public int32 mVal;
|
||||||
|
|
||||||
|
[Bitfield<uint8>(.Public, .AutoRev, "E")]
|
||||||
|
[Bitfield<uint8>(.Public, .BitsRev(8), "F")]
|
||||||
|
[Bitfield<uint8>(.Public, .ValueRangeRev(0..<256), "G")]
|
||||||
|
[Bitfield<uint8>(.Public, .BitsAt(8, 0), "H")]
|
||||||
|
public int32 mVal2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
static void TestBasics()
|
||||||
|
{
|
||||||
|
Test.Assert(sizeof(StructA) == 8);
|
||||||
|
StructA sa = .();
|
||||||
|
sa.A = 0x12;
|
||||||
|
sa.B = 7;
|
||||||
|
sa.C = .C;
|
||||||
|
sa.D = 9;
|
||||||
|
sa.E = 0x22;
|
||||||
|
sa.F = 0x33;
|
||||||
|
sa.G = 0x44;
|
||||||
|
sa.H = 0x55;
|
||||||
|
Test.Assert(sa.A == 0x12);
|
||||||
|
Test.Assert(sa.B == 7);
|
||||||
|
Test.Assert(sa.C == .C);
|
||||||
|
Test.Assert(sa.D == 9);
|
||||||
|
|
||||||
|
Test.Assert(sa.mVal == 0x0025FF12);
|
||||||
|
Test.Assert(sa.mVal2 == 0x22334455);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue