Search Forum
(57415 Postings)
Search Site/Articles

Archived Articles
712 Articles

C# Books
C# Consultants
What Is C#?
Download Compiler
Code Archive
Archived Articles
Advertise
Contribute
C# Jobs
Beginners Tutorial
C# Contractors
C# Consulting
Links
C# Manual
Contact Us
Legal

GoDiagram for .NET from Northwoods Software www.nwoods.com


              
Printable Version

Byteset In C#
By S. Lee Odegard

Here is a C# struct byteset that implements the Modula-3 type SET OF BYTE. A set is a collection of values taken from an ordinal type that has a manageable number of possible values; which in this case are values of the range 0 to 255 inclusive.  The set-valued operators +(set union), -(set difference), *(set intersection), and /(symmetric set difference), and the set-valued subset relations <=  >=  < , and > are also implemented.  The set membership relation (e is-an-element-of b) for a byte e and byteset b is mapped to the % operator: e%b .

For an example, consider the output:

	bs3= ( 0, 19, 38, 57, 76, 95, 114,
	 133, 152, 171, 190, 209, 228, 247 ) [14 items]
	   <= True bs6= ( 0, 38, 76, 114, 152, 190, 228 ) [7 items]
	bs3-bs6 = ( 19, 57, 95, 133, 171, 209, 247 ) [7 items]
	bs6 items: 0 38 76 114 152 190 228 sum to 798

This is produced by the following method that employs byteset:

	class s{ public static string tout{ set{ Console.Write( value );}}}
	class Class1
	{
		[STAThread]
		static void Main(string[] args)
		{

	byteset bs3= byteset.Empty;
	for( int i= 0; i<256; i+= 19 ){ bs3+= (byte)i;}

	byteset bs6= byteset.Empty;
	for( int i= 0; i<256; i+= 38 ){ bs6+= (byte)i;}

	s.tout= "bs3= " + bs3.ToString() + " [" + bs3.GetModulus().ToString() 
	+ " items]\r\n   <= " + (bs3<=bs6).ToString() + " bs6= " 
	+ bs6.ToString() + " [" + bs6.GetModulus().ToString() 
	+ " items]\r\n" ;

	bs3-= bs6;
	s.tout= "bs3-bs6 = " + bs3.ToString() 
	+ " [" + bs3.GetModulus().ToString() + " items]\r\n";

	int result= 0;
	s.tout= "bs6 items: ";
	foreach( byte i in bs6 ){
		result+= i;
		s.tout= i.ToString() + " ";}
	s.tout= " sum to " + result.ToString()+ "\r\n\r\n";
	string ig= Console.ReadLine();//hold console open, then quit

		}//Main
	}//Class1
In the examples, s.tout may also be an accessor that appends text to the main textbox in a Windows form.  In that case, the final Console.ReadLine() may be omitted.  Similar code has been employed to generate Modula-3 programs with assertion statements on random sets to validate this C# implementation.

The following employs the byteset type to calculate the prime numbers < 255 as well as show some of the numbers sieved out in the process:

	byteset bs1= byteset.FromRange( 2, 255 );
	for( int i= 4; i<256; i+=2 ){//exclude even numbers except 2
		bs1-= (byte)i;}
	byteset bse;

	byte[] sp= {3, 5, 7, 11, 13};
	foreach( byte j in sp )
	{
		bse= bs1;
		for( int i= j*j; i<256; i+=2*j ){
			bs1-= (byte)i;}
		if( j>5 )
		{
			bse-= bs1;
			s.tout= "sieve " + j.ToString() + ": " + bse.ToString() + "\r\n";
			s.tout= "delta ";
			int delta= 0;
			foreach( byte k in bse ){
				s.tout= ( k-delta ).ToString() + " ";  delta= k;}
			s.tout= "\r\n\r\n";
		}
	}
	s.tout= "primes < 255 are " + bs1.ToString() + "\r\n\r\n";

This has the output:

	sieve 7: ( 49, 77, 91, 119, 133, 161, 203, 217 )
	delta 49 28 14 28 14 28 42 14

	sieve 11: ( 121, 143, 187, 209, 253 )
	delta 121 22 44 22 44

	sieve 13: ( 169, 221, 247 )
	delta 169 52 26

	primes < 255 are ( 2, 3, 5, 7, 11, 13, 17, 19,
	  23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
	  71, 73, 79, 83, 89, 97, 101, 103, 107, 109,
	  113, 127, 131, 137, 139, 149, 151, 157, 163,
	  167, 173, 179, 181, 191, 193, 197, 199, 211,
	  223, 227, 229, 233, 239, 241, 251 )

The byteset struc follows:

using System;
using System.Collections;
using System.Runtime.InteropServices;

	/// <summary>
 	/// <p>A set representation that can contain up to 256 elements from 0..255</p>
 	/// <p>Comments? Questions? Bugs? Tell S. Lee Odegard, leeo@bossig.com</p>
	/// <p>Version: May 1, 2002</p>
	/// </summary>
	[StructLayout(LayoutKind.Sequential)]
	public struct byteset : ICloneable, IEnumerable
	{
		/// <summary>
		/// byteset supports 256 elements in the range 0..255
		/// </summary>
		ulong bs0, bs1, bs2, bs3;
		const byte mask = 0x3F;//2_00111111

#region constructors FromBytes, FromRange, byteset, Clone
		/// <summary>
		/// Create a byteset from bytes (unsigned short integer)
		/// </summary>
		/// <param name="item"></param>
		static public byteset FromBytes( params byte[] i ) 
		{
			byteset b;
			b.bs0= 0UL;  b.bs1= 0UL;  b.bs2= 0UL;  b.bs3= 0UL;
			foreach( byte j in i ){ switch( j>>6 )
			{
				case 0: b.bs0|= 1UL<<j;break;
				case 1: b.bs1|= 1UL<<(j&mask);break;
				case 2: b.bs2|= 1UL<<(j&mask);break;
				case 3: b.bs3|= 1UL<<(j&mask);break;
			}}
			return b;
		}


		static private ulong drapeFromUintRange( byte from, byte to, byte max )
		{
			if( from > to || from > max ){ return 0UL;}
			to= to > max? max: to;
			return ( unchecked( (ulong)-1 )>>(63-to+from) )<<from;

#if design_code
			res= 0UL;
			for( int i= from; i<=to; i++){ res|= 1UL<<i;}
			return res;
#endif
		}

		/// <summary>
		/// Create a byteset that includes the items in the range from..to
		/// </summary>
		/// <param name="from"></param>
		/// <param name="to"></param>
		/// <returns></returns>
		static public byteset FromRange( byte from, byte to )
		{
			byteset b= byteset.Empty;

			// divide into sections: 0..63; 64..127; 128..191; 192..255;
			// i.e. 60..150 -> 60..63, 64..127, 128..150
			// 100..150 -> <64>100..127, 128..150<191>
			// 200..250 -> <192>200..250<255>
			if( from < 64 ){ 
				b.bs0= drapeFromUintRange( from, to, 63);
				from= 64;}
			if( from < 128 ){ 
				b.bs1= drapeFromUintRange( from, to, 127);
				from= 128;}
			if( from < 192 ){ 
				b.bs2= drapeFromUintRange( from, to, 191);
				from= 192;}
			b.bs3= drapeFromUintRange( from, to, 255);
			return b;

#if design_code
			byteset b= byteset.Empty;
			for( int i= from; i<=to; i++ ){ b+= (byte)i;}
			return b;
#endif
		}

		/// <summary>
		/// Create a byteset from array bytes (unsigned short integer)
		/// </summary>
		/// <param name="i"></param>
		public byteset( params byte[] i )
		{
			this.bs0= 0UL;  this.bs1= 0UL;  this.bs2= 0UL;  this.bs3= 0UL;
			foreach( byte j in i ){ switch( j>>6 )
			{
			case 0: this.bs0|= 1UL<<j;break;
			case 1: this.bs1|= 1UL<<(j&mask);break;
			case 2: this.bs2|= 1UL<<(j&mask);break;
			case 3: this.bs3|= 1UL<<(j&mask);break;
			}}
		}

		/// <summary>
		/// Create a byteset copying from an existing byteset
		/// </summary>
		/// <param name="b"></param>
		public byteset( byteset b ){
			this.bs0= b.bs0;  this.bs1= b.bs1;
			this.bs2= b.bs2;  this.bs3= b.bs3;}


		object ICloneable.Clone(){ return new byteset( this );}
		public byteset Clone(){ return new byteset( this );}
#endregion
		
		//---------------------------------------------------------------------------------
		//---------------------------------------------------------------------------------
		/// <summary>
		/// Get byteset hash code
		/// </summary>
		/// <returns></returns>
		public override int GetHashCode(){
			return this.bs0.GetHashCode() ^ this.bs1.GetHashCode()
				^ this.bs2.GetHashCode() ^ this.bs3.GetHashCode();}


		private byte ulongmodulus( ulong x )
		{
			const ulong mask = 0xFUL;
			byte result= (byte)0;
			for( int i= 0; i < 16; i++ )
			{
				switch( x & mask )
				{
				case 0: break;
				case 1: case 2: case 4: case 8: result+= (byte)1; break;
				case 3: case 5: case 6: 
				case 9: case 10: case 12: result+= (byte)2; break;
				case 7: case 11: case 13: case 14: result+= (byte)3; break;
				case 15: result+= (byte)4; break;
				}
				x>>= 4;
			}
			return result;
		}

		/// <summary>
		/// Get modulus (number of items) in byteset
		/// </summary>
		/// <returns></returns>
		public byte GetModulus()
		{
			return (byte)(ulongmodulus( this.bs0 ) + ulongmodulus( this.bs1 )
				+ ulongmodulus( this.bs2 ) + ulongmodulus( this.bs3 ));
#if design_code
			byte res= (byte)0;
			for( int i= 0; i<256; i++ ){ if( i % this ){ res+= 1;}}
			return (byte)res;
#endif
		}


#region byteset relations == != <= >= < >
		/// <summary>
		/// this byteset equivalent to another object?
		/// </summary>
		/// <param name="o"></param>
		/// <returns></returns>
		public override bool Equals( object o ){
			if( o is byteset ){
				byteset b= (byteset) o;
				return this == b;}
			return false;}		
		
		/// <summary>
		/// Are these two bytesets equivalent?
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator==( byteset a, byteset b ){
			return a.bs0 == b.bs0 && a.bs1 == b.bs1
				&& a.bs2 == b.bs2 && a.bs3 == b.bs3;}

		/// <summary>
		/// Are these two bytesets different?
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator!=( byteset a, byteset b ){
			return a.bs0 != b.bs0 || a.bs1 != b.bs1
				|| a.bs2 != b.bs2 || a.bs3 != b.bs3;}

		
		/// <summary>
		/// subset: a<=b == every element of byteset a is also an element of byteset b
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator<=( byteset a, byteset b ){
			return (~b.bs0 | a.bs0) != 0UL || (~b.bs1 | a.bs1) != 0UL
				|| (~b.bs2 | a.bs2) != 0UL || (~b.bs3 | a.bs3) != 0UL;}

		public static bool operator>=( byteset a, byteset b ){
			return (~a.bs0 | b.bs0) != 0UL || (~a.bs1 | b.bs1) != 0UL
				|| (~a.bs2 | b.bs2) != 0UL || (~a.bs3 | b.bs3) != 0UL;}

		public static bool operator<( byteset a, byteset b ){
			return (a<=b) && (a!=b);}

		public static bool operator>( byteset a, byteset b ){
			return (a>=b) && (a!=b);}
#endregion	
		
#region byteset operators ~ % + - * /
		/// <summary>
		/// Set complement, e%(~b) == ~( e % b ); e in ~b == e not in b
		/// </summary>
		/// <param name="e"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static byteset operator~( byteset b ){
			b.bs0 = ~b.bs0;  b.bs1 = ~b.bs1;  b.bs2= ~b.bs2;  b.bs3= ~b.bs3;
			return b;}

		/// <summary>
		/// Set membership, IN: e%b is true == byte e is an element of byteset b
		/// </summary>
		/// <param name="e"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static bool operator%( byte e, byteset b ) 
		{ //element e is _in_ set b
			switch( e>>6 )
			{
			case 0: return (1UL<<e & b.bs0) != 0UL;
			case 1: return (1UL<<(e&mask) & b.bs1) != 0UL;
			case 2: return (1UL<<(e&mask) & b.bs2) != 0UL;
			case 3: return (1UL<<(e&mask) & b.bs3) != 0UL;
			} return false;//placate warning about paths to return statement
		}
				
		/// <summary>
		/// Set union: e%(x+y) == e%x or e%y
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static byteset operator+( byteset a, byteset b ){
			a.bs0|= b.bs0;  a.bs1|= b.bs1;  a.bs2|= b.bs2;  a.bs3|= b.bs3;
			return a;}

		/// <summary>
		/// include in byteset a element e: useful for += assignment
		/// </summary>
		/// <param name="a"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		public static byteset operator+( byteset a, byte e )
		{
			switch( e>>6 )
			{
			case 0: a.bs0|= 1UL<<(e&mask);break;
			case 1: a.bs1|= 1UL<<(e&mask);break;
			case 2: a.bs2|= 1UL<<(e&mask);break;
			case 3: a.bs3|= 1UL<<(e&mask);break;
			}
			return a;
		}

		/// <summary>
		/// Set difference: e%(x-y) == e%x and not e%y
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static byteset operator-( byteset a, byteset b ){
			a.bs0&= ~b.bs0;  a.bs1&= ~b.bs1;  a.bs2&= ~b.bs2;  a.bs3&= ~b.bs3;
			return a;}

		/// <summary>
		/// exclude from byteset a element e: useful for -= assignment
		/// </summary>
		/// <param name="a"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		public static byteset operator-( byteset a, byte e )
		{
			switch( e>>6 )
			{
			case 0: a.bs0&= ~(1UL<<(e&mask));break;
			case 1: a.bs1&= ~(1UL<<(e&mask));break;
			case 2: a.bs2&= ~(1UL<<(e&mask));break;
			case 3: a.bs3&= ~(1UL<<(e&mask));break;
			}
			return a;
		}

		/// <summary>
		/// Set intersection: e%(x*y) == e%x and e%y
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static byteset operator*( byteset a, byteset b ){
			a.bs0&= b.bs0;  a.bs1&= b.bs1;  a.bs2&= b.bs2;  a.bs3&= b.bs3;
			return a;}
		
		/// <summary>
		/// Symmetric set difference: e%(x/y) == e%x != e%y
		/// </summary>
		/// <param name="a"></param>
		/// <param name="b"></param>
		/// <returns></returns>
		public static byteset operator/( byteset a, byteset b ){
			a.bs0^= b.bs0;  a.bs1^= b.bs1;  a.bs2^= b.bs2;  a.bs3^= b.bs3;
			return a;}
#endregion

#region byteset string conversions Parse (unimplemented) and ToString
		/// <summary>
		/// Parse a byteset representation in this fashion: "( %b, %b, %b )"
		/// </summary>
		/// <param name="s"></param>
		/// <returns></returns>
		static public byteset Parse( string s ){
			throw new NotImplementedException( 
				"byteset byteset.Parse( string s ) is not implemented." );}
		
		/// <summary>
		/// Get the string representation
		/// </summary>
		/// <returns></returns>
		public override string ToString(){ return ToString( '(', ')' );}
		public string ToString( char delimiterL, char delimiterR ) 
		{
			string output= delimiterL.ToString();
			ulong bsa= 1UL;
			bool h0= false;
			for( int i= 0; i < 64; i++){
				if( (this.bs0 & bsa)!=0){
					output+= (h0? ", " : " ") + i.ToString();
					h0= true;}
				bsa <<= 1;}
			bsa= 1UL;
			for( int i= 0; i < 64; i++){
				if( (this.bs1 & bsa)!=0){
					output+= (h0? ", " : " ") + (i+64).ToString();
					h0= true;}
				bsa <<= 1;}
			bsa= 1UL;
			for( int i= 0; i < 64; i++){
				if( (this.bs2 & bsa)!=0){
					output+= (h0? ", " : " ") + (i+128).ToString();
					h0= true;}
				bsa <<= 1;}
			bsa= 1UL;
			for( int i= 0; i < 64; i++){
				if( (this.bs3 & bsa)!=0){
					output+= (h0? ", " : " ") + (i+192).ToString();
					h0= true;}
				bsa <<= 1;}
			return output + " " + delimiterR.ToString() ;
		}

		public string ToStringCompact(){
			return this.bs0.ToString( "X" ) + this.bs1.ToString( "X" )
				+ this.bs2.ToString( "X" ) + this.bs3.ToString( "X" );}
#endregion

#region byteset static values Empty, Full and the equivalent MinValue, MaxValue
		/// <summary>
		/// Empty set
		/// </summary>
		static public byteset Empty{
		get{
			byteset b;  b.bs0= 0;  b.bs1= 0;  b.bs2= 0;  b.bs3= 0;
			return b;
		}}

		/// <summary>
		/// Full set
		/// </summary>
		static public byteset Full{
		get{
			const ulong ff= unchecked( (ulong)-1 );
			byteset b;
			b.bs0= ff;  b.bs1= ff;  b.bs2= ff;  b.bs3= ff;
			return b;}}

		/// <summary>
		/// Smallest possible byteset value or empty set
		/// </summary>
		static public byteset MinValue{ get{ return byteset.Empty;}}

		/// <summary>
		/// Largest possible byteset value or full set
		/// </summary>
		static public byteset MaxValue{ get{ return byteset.Full;}}
#endregion

		//---------------------------------------------------------------------------------
		//---------------------------------------------------------------------------------
		public IEnumerator GetEnumerator(){ return new bytesetEnumerator( this );}
		private class bytesetEnumerator : IEnumerator
		{
			private int position = -1;
			private byteset b;

			public bytesetEnumerator(byteset b){ this.b = b;}

			public bool MoveNext(){
				while( ++position < 256 && !((byte)(position)%b) ){};
				return position < 256;}

			public void Reset(){ position = -1;}
			byte Current{ get{ return (byte)position;}}
			object IEnumerator.Current{ get{ return (byte)position;}}
		}
	}