C Sharp sorting considered superior to C by an order of magnitude
- From: spinoza1111 <spinoza1111@xxxxxxxxx>
- Date: Sun, 24 Feb 2008 07:23:00 -0800 (PST)
Here's the first version of a C sharp program that addresses the
issues raised last month in a discussion of sorting: a visual sorting
lab based on a sort object.
The code, at the end of this post, is best viewed in a monospaced font
such as Courier New.
If you have questions, ask them here or email me at
spinoza1111@xxxxxxxxxx Online thugs may flame and be damned.
This application and form demonstrates, visually and in code the
following sort algorithms and the following points.
* Bubble sort
* Interchange sort
* Quicksort
* Superiority of quicksort over bubble and interchange sort even for
small amounts of data: the visual sort provided demonstrates that the
quicksort is considerably faster than interchange and bubble sorting
for random data, and even somewhat faster for already sorted data as
its recursion winds down.
* Superiority of interchange sort when it's necessary to get topmost
entries as opposed to a complete sorted table, as opposed to the
bubble sort
* Overwhelming superiority of C Sharp to C: one sort class provides
multiple ways of sorting and sorts *anything* using a generic
parameter
This code contains no intentional viruses, Trojans or other malicious
technology.
To use this code
1. Acquire Visual Studio Express 2008 free from at www.microsoft.COM.
2. After installation, create a Windows project. Click the
blank form that is presented in design mode. Paste all the code in
this file in the code window shown, replacing all the existing code.
3. Press F5 to compile and run to see a form with multiple
blocks of different colors, each labeled with the RGB code for the
color therein. Look at the buttons and try them out in any order, to
create new block sets, or to sort the blocks visually by the RGB
code.
Notice how slow the bubble sort runs, and also that it fails to find
the "interesting" top ranked (lowest RGB) entries. Note that the
interchange sort finds these fast. Note that the quicksort runs fast
unless it is clicked twice (sorting a sequenced nonrandom table the
second time), although it speeds up visually with respect to
interchange and bubble.
Note that the sort speed differences are obvious. C programmers have
(as a reliable part of the language) only crude timers which fail to
show much differences in most benchmarks unless the sorted array is
large (1K+ entries) leading to the false belief that it's justified to
code an interchange or bubble sort for arrays between about 100 and
1000 entries.
The colors will seem to be out of order, but this because RGB doesn't
correspond to what you see. The numbers are ordered from the smallest
RGB to the largest where red is sorted before green and green before
blue.
Note also that the enclosed sort class can sort ANYTHING as opposed to
C in which in general a new set of sorded sorts has to be provided for
each new data type, leading to rather Neolithic scenes in which C
programmers triumphantly reinvent the bubble sort for a new struct.
The sort class can sort ANYTHING because it has a generic parameter,
the type of each entry in the sorted array.
The Neolithic scenes also include, often enough, misery around
actually moving large structures although considered in purity of
heart, sorting has nothing more to do with tidily arranging things,
moving them about the shop, than can submarines swim: sorting is a
problem in retrieval in which motion of bytes needs to be eliminated
or reduced.
The object-orientation of this code avoids dragging large blocks about
using memcpy, because in all cases the array passed to instances of
the sort class contains either fixed-size and small stackable values
(at worst, long integers and double precision floating point numbers),
or else references, that is addresses, to larger heap structures which
are NOT moved.
In fact, what's sorted are labels, which have hundreds of properties.
The user provides "Callbacks" in the form of event handlers making the
actual comparision, but as a feature which I haven't tested, the sort
class presented will detect when no sort logic is provided and provide
its own comparision for the types bool, byte, short, int, long,
single, double and string.
Here is the code.
//
********************************************************************
// *
*
// * Sort evaluation lab for comp.programming
*
// *
*
//
********************************************************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace cpSort
{
public partial class Form1 : Form
{
// ***** State *****
private CheckBox CHKdeterminism;
private Label[] LBLarray;
private Random OBJrandom;
// ***** Events
************************************************
public Form1()
{
InitializeComponent();
this.Load += Form1_Load;
}
// ***** Events
************************************************
private void CHKdeterminism_Click(object objSender,
EventArgs objEventArgs)
{
OBJrandom = mkRandom(CHKdeterminism.Checked);
}
private void cmdBubbleSort_Click(object objSender,
EventArgs objEventArgs)
{
bubbleSortTest();
}
private void cmdClose_Click(object objSender,
EventArgs objEventArgs)
{
closer();
}
private void cmdInterchangeSort_Click
(object objSender,
EventArgs objEventArgs)
{
interchangeSortTest();
}
private void cmdMakeNewArray_Click(object objSender,
EventArgs objEventArgs)
{
recolorLabels(LBLarray);
}
private void cmdQuickSort_Click(object objSender,
EventArgs objEventArgs)
{
quickSortTest();
}
private void Form1_Load(object objSender,
EventArgs objEventArgs)
{
OBJrandom = mkRandom(true);
if (OBJrandom == null) closer();
if (!customizeForm()) closer();
}
// --------------------------------------------------------
// colorCompareEvent handler
//
//
private void colorCompareEventHandler
(object objSender,
Label objComparand1,
Label objComparand2,
int intComparand1Index,
int intComparand2Index,
ref int intCompareResult)
{
if (objComparand1.BackColor.R
>
objComparand2.BackColor.R)
{
intCompareResult = 1;
}
else
{
if (objComparand1.BackColor.R
<
objComparand2.BackColor.R)
{
intCompareResult = -1;
}
else
{
if (objComparand1.BackColor.G
>
objComparand2.BackColor.G)
{
intCompareResult = 1;
}
else
{
if (objComparand1.BackColor.G
<
objComparand2.BackColor.G)
{
intCompareResult = -1;
}
else
{
if (objComparand1.BackColor.B
>
objComparand2.BackColor.B)
{
intCompareResult = 1;
}
else
{
if (objComparand1.BackColor.B
<
objComparand2.BackColor.B)
{
intCompareResult = -1;
}
else
{
intCompareResult = 0;
}
}
}
}
}
}
eventHighlight(objComparand1,
objComparand2,
20,
FontStyle.Bold,
true);
}
// --------------------------------------------------------
// exchangeEvent handler
//
//
private void exchangeEventHandler
(object objSender,
int intIndex1,
int intIndex2)
{
Point objExchanger = new Point(LBLarray[intIndex2].Left,
LBLarray[intIndex2].Top);
LBLarray[intIndex2].Left = LBLarray[intIndex1].Left;
LBLarray[intIndex2].Top = LBLarray[intIndex1].Top;
LBLarray[intIndex1].Left = objExchanger.X;
LBLarray[intIndex1].Top = objExchanger.Y;
LBLarray[intIndex1].Refresh();
LBLarray[intIndex2].Refresh();
}
// ***** General procedures
***********************************
// --------------------------------------------------------
// Background to foreground color
//
//
private static Color bg2fgColor(Color objColor)
{
if (objColor.GetBrightness() > .75) return Color.Black;
return Color.White;
}
//
------------------------------------------------------------
// Bubble sort test
//
//
private bool bubbleSortTest()
{
resetLabels(LBLarray);
sort<Label> objLabelSorter =
new sort<Label>
(sort<Label>.ENUalgorithm.bubbleSort);
objLabelSorter.compareEvent += colorCompareEventHandler;
objLabelSorter.exchangeEvent += exchangeEventHandler;
bool booReturn = objLabelSorter.sortArray(LBLarray);
objLabelSorter.dispose();
string strHelp = "";
if (!checkSequence(LBLarray, ref strHelp))
return utilities.errorHandler
("Sequence error after bubble sort",
this.Name,
"bubbleSortTest",
utilities.separateStrings
("Returning false", strHelp));
return booReturn;
}
// --------------------------------------------------------
// Check LBLarray sequence
//
//
private static bool checkSequence
(Label[] lblArray,
ref string strExplanation)
{
int intIndex1;
int intIndex2;
strExplanation = "";
for (intIndex1 = 0;
intIndex1 < lblArray.GetUpperBound(0);
intIndex1++)
{
intIndex2 = intIndex1 + 1;
if (lblArray[intIndex1].BackColor.ToArgb()
>
lblArray[intIndex1 + 1].BackColor.ToArgb())
{
strExplanation =
"Sequence error after index " +
intIndex1.ToString();
break;
}
if (lblArray[intIndex1].Top
>
lblArray[intIndex2].Top
||
(lblArray[intIndex1].Top
==
lblArray[intIndex2].Top
&&
lblArray[intIndex1].Left
>
lblArray[intIndex2].Left))
{
strExplanation =
"Label position sequence error after " +
"index " + intIndex1.ToString();
break;
}
}
if (intIndex1 >= lblArray.GetUpperBound(0)) return true;
return utilities.errorHandler
("A sequence check has found " +
"programming-originated errors in " +
"the array of test labels",
"cpSort",
"checkSequence()",
utilities.separateStrings
("Returning false", strExplanation));
}
//
------------------------------------------------------------
// Close application
//
//
private void closer()
{
this.Dispose();
Application.Exit();
}
// --------------------------------------------------------
// Randomly color one label
//
//
private static void colorLabel(Random OBJrandom,
Label lblLabel)
{
lblLabel.BackColor = Color.Red;
int intAdjust = OBJrandom.Next(200);
switch (OBJrandom.Next(7))
{
case 0:
{
lblLabel.BackColor =
Color.FromArgb(Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0),
255),
0,
0);
break;
}
case 1:
{
lblLabel.BackColor =
Color.FromArgb(0,
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255),
0);
break;
}
case 2:
{
lblLabel.BackColor =
Color.FromArgb(0,
0,
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255));
break;
}
case 3:
{
lblLabel.BackColor =
Color.FromArgb(Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0),
255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255),
0);
break;
}
case 4:
{
lblLabel.BackColor =
Color.FromArgb(0,
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255));
break;
}
case 5:
{
lblLabel.BackColor =
Color.FromArgb(Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0),
255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255));
break;
}
case 6:
{
lblLabel.BackColor =
Color.FromArgb(Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0),
255),
0,
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255));
break;
}
case 7:
{
lblLabel.BackColor =
Color.FromArgb(Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0),
255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255),
Math.Min(Math.Max(OBJrandom.Next(255) + intAdjust, 0), 255));
break;
}
default:
{
MessageBox.Show("Unexpected switch statement
flow: " +
"application terminated");
Application.Exit();
break;
}
}
lblLabel.ForeColor = bg2fgColor(lblLabel.BackColor);
lblLabel.Text =
lblLabel.BackColor.R.ToString() + " " +
lblLabel.BackColor.G.ToString() + " " +
lblLabel.BackColor.B.ToString();
lblLabel.Refresh();
return;
}
// --------------------------------------------------------
// Create a label template based on a factor applied to
// width and height
//
//
private Label createLabelTemplate(Double dblFactor)
{
try
{
Label lblNew = new Label();
lblNew.Width = (int)(lblNew.Width * dblFactor);
lblNew.Height = (int)(lblNew.Height * dblFactor);
lblNew.TextAlign = ContentAlignment.MiddleCenter;
lblNew.Font = new Font(lblNew.Font, FontStyle.Bold);
return lblNew;
}
catch (Exception objException)
{
utilities.errorHandler
("Cannot make label template",
this.Name,
"createLabelTemplate()",
"Returning null",
objException);
return null;
}
}
//
------------------------------------------------------------
// Tailor the form
//
//
private const Double WIDTH_TOLERANCE = .99;
private const Double HEIGHT_TOLERANCE = .95;
private const Double LABEL_SIZE_FACTOR = 2;
private bool customizeForm()
{
try
{
this.Text = Application.ProductName;
this.FormBorderStyle = FormBorderStyle.Fixed3D;
this.MinimizeBox = false;
this.MaximizeBox = false;
this.ControlBox = false;
this.Width =
(int)(windowsUtilities.screenWidth()
*
WIDTH_TOLERANCE);
this.Height =
(int)(windowsUtilities.screenHeight()
*
HEIGHT_TOLERANCE);
this.CenterToParent();
int intGrid = 8;
// --- Create determinism check box
int intLeft = intGrid;
CHKdeterminism = new CheckBox();
CHKdeterminism.Left = intLeft;
CHKdeterminism.Top = intGrid;
CHKdeterminism.Text = "Deterministic arrays";
CHKdeterminism.Width <<= 1;
CHKdeterminism.Checked = true;
this.Controls.Add(CHKdeterminism);
CHKdeterminism.Click += CHKdeterminism_Click;
intLeft += CHKdeterminism.Width + intGrid;
// --- Create button to make a new array
Button cmdNew = new Button();
cmdNew.Left = intLeft;
cmdNew.Top = intGrid;
cmdNew.Text = "New array";
cmdNew.Click += cmdMakeNewArray_Click;
this.Controls.Add(cmdNew);
intLeft += cmdNew.Width + intGrid;
// --- Bubble sort test
cmdNew = new Button();
cmdNew.Left = intLeft;
cmdNew.Top = intGrid;
cmdNew.Text = "Bubble sort";
cmdNew.Click += cmdBubbleSort_Click;
this.Controls.Add(cmdNew);
intLeft += cmdNew.Width + intGrid;
// --- Interchange sort test
cmdNew = new Button();
cmdNew.Left = intLeft;
cmdNew.Top = intGrid;
cmdNew.Text = "Interchange sort";
cmdNew.Click += cmdInterchangeSort_Click;
this.Controls.Add(cmdNew);
intLeft += cmdNew.Width + intGrid;
// --- Quicksort test
cmdNew = new Button();
cmdNew.Left = intLeft;
cmdNew.Top = intGrid;
cmdNew.Text = "Quicksort";
cmdNew.Click += cmdQuickSort_Click;
this.Controls.Add(cmdNew);
intLeft += cmdNew.Width + intGrid;
// --- Create sort labels
mkLabelArray(intGrid,
cmdNew.Bottom + intGrid,
LABEL_SIZE_FACTOR);
// --- Adjust form
this.ClientSize =
new Size(LBLarray[LBLarray.GetUpperBound(0)].Right
+
intGrid,
LBLarray[LBLarray.GetUpperBound(0)].Bottom
+
intGrid);
// --- Create close button
cmdNew = new Button();
cmdNew.Left = this.ClientSize.Width
-
intGrid
-
cmdNew.Width;
cmdNew.Top = intGrid;
cmdNew.Text = "Close";
cmdNew.Click += cmdClose_Click;
this.Controls.Add(cmdNew);
CenterToScreen();
Refresh();
return true;
}
catch (System.Exception objException)
{
return utilities.errorHandler
("Cannot customize form",
this.Name,
"customizeForm()",
"Returning false",
objException,
true);
}
}
//
------------------------------------------------------------
// Event font highlight
//
//
// Places old font in Tag of label passed
//
//
private void eventHighlight(Label lblLabel1,
Label lblLabel2,
float dblEmsize,
FontStyle objStyle)
{
eventHighlight(lblLabel1,
lblLabel2,
dblEmsize,
objStyle,
false);
}
// --- Option to save old font to Tag
private void eventHighlight(Label lblLabel1,
Label lblLabel2,
float dblEmsize,
FontStyle objStyle,
bool booSaveToTag)
{
if (booSaveToTag)
{
if (!labelHasFontTag(lblLabel1))
lblLabel1.Tag = lblLabel1.Font;
if (!labelHasFontTag(lblLabel1))
lblLabel2.Tag = lblLabel2.Font;
}
lblLabel1.Font = new Font(lblLabel1.Font.FontFamily,
dblEmsize,
objStyle);
lblLabel1.Refresh();
lblLabel2.Font = new Font(lblLabel2.Font.FontFamily,
dblEmsize,
objStyle);
lblLabel2.Refresh();
pauser();
}
//
------------------------------------------------------------
// Interchange sort test
//
//
private bool interchangeSortTest()
{
resetLabels(LBLarray);
sort<Label> objLabelSorter =
new sort<Label>
(sort<Label>.ENUalgorithm.interchangeSort);
objLabelSorter.compareEvent += colorCompareEventHandler;
objLabelSorter.exchangeEvent += exchangeEventHandler;
bool booReturn = objLabelSorter.sortArray(LBLarray);
objLabelSorter.dispose();
string strHelp = "";
if (!checkSequence(LBLarray, ref strHelp))
return utilities.errorHandler
("Sequence error after interchange sort",
this.Name,
"bubbleSortTest",
utilities.separateStrings
("Returning false", strHelp));
return booReturn;
}
// --------------------------------------------------------
// Tell caller whether label has a font tag
//
//
private bool labelHasFontTag(Label lblLabel)
{
return lblLabel.Tag != null
&&
lblLabel.Tag.GetType().ToString()
==
(new Font(this.Font,
FontStyle.Regular)).GetType().ToString();
}
// --------------------------------------------------------
// Create or expand the label array
//
//
// Grows the label array from the last entry when it
// already exists. Creates and builds it otherwise.
//
//
private bool mkLabelArray(int intGrid,
int intGridTop,
double dblSizeFactor)
{
try
{
int intLeft = intGrid;
int intTop = intGridTop;
int intRightMargin = ClientSize.Width - intGrid;
Label lblNext;
int intStartIndex = this.Controls.Count;
int intNextTop;
while (true)
{
lblNext = createLabelTemplate(dblSizeFactor);
lblNext.Left = intLeft; lblNext.Top = intTop;
lblNext.BorderStyle = BorderStyle.Fixed3D;
colorLabel(OBJrandom, lblNext);
this.Controls.Add(lblNext);
lblNext.Refresh();
intLeft += lblNext.Width;
if (intLeft + lblNext.Width
>
intRightMargin)
{
intLeft = intGrid;
if ((intNextTop
=
intTop + lblNext.Height)
>
ClientSize.Height - intGrid) break;
intTop = intNextTop;
}
}
LBLarray = new Label[this.Controls.Count
-
intStartIndex];
int intIndex1;
for (intIndex1 = intStartIndex;
intIndex1 < this.Controls.Count;
intIndex1++)
LBLarray[intIndex1 - intStartIndex] =
(Label)(this.Controls[intIndex1]);
return true;
}
catch (Exception objException)
{
return utilities.errorHandler
("Cannot create label array",
this.Name,
"mkLabelArray()",
"Returning false",
objException);
}
}
//
------------------------------------------------------------
// Make a random number generator
//
//
private Random mkRandom(bool booDeterminism)
{
try
{
if (booDeterminism) return new Random(1);
return new Random();
}
catch (Exception objException)
{
utilities.errorHandler("Cannot create Random object",
this.Name,
"mkRandom()",
"Returning null",
objException);
return null;
}
}
//
------------------------------------------------------------
// Pauser
//
//
private static void pauser()
{
System.Threading.Thread.Sleep(1);
}
//
------------------------------------------------------------
// Quick sort test
//
//
private bool quickSortTest()
{
resetLabels(LBLarray);
sort<Label> objLabelSorter =
new sort<Label>
(sort<Label>.ENUalgorithm.quickSort);
objLabelSorter.compareEvent += colorCompareEventHandler;
objLabelSorter.exchangeEvent += exchangeEventHandler;
bool booReturn = objLabelSorter.sortArray(LBLarray);
objLabelSorter.dispose();
string strHelp = "";
if (!checkSequence(LBLarray, ref strHelp))
return utilities.errorHandler("Sequence error",
this.Name,
"quickSortTest",
utilities.separateStrings
("Returning false",
strHelp));
return true;
}
//
------------------------------------------------------------
// Recolor labels
//
//
// --- Recolor all labels
private bool recolorLabels(Label[] lblArray)
{
return recolorLabels(lblArray,
0,
lblArray.GetUpperBound(0));
}
// --- Recolor some labels
private bool recolorLabels(Label[] lblArray,
int intStartIndex,
int intCount)
{
if (OBJrandom == null) return false;
int intIndex1;
for (intIndex1 = intStartIndex;
intIndex1 < intStartIndex + intCount;
intIndex1++)
{
colorLabel(OBJrandom, lblArray[intIndex1]);
resetLabels(LBLarray, intIndex1, 1);
}
return true;
}
//
--------------------------------------------------------------------
// Reset the label fonts
//
//
// --- Reset all fonts
private void resetLabels(Label[] lblArray)
{
resetLabels(lblArray, 0, lblArray.GetUpperBound(0) + 1);
pauser();
}
// --- Reset a subset (in practice, one)
private void resetLabels(Label[] lblArray,
int intStartIndex,
int intCount)
{
int intIndex1;
int intEndIndex = intStartIndex + intCount - 1;
for (intIndex1 = intStartIndex;
intIndex1 <= intEndIndex;
intIndex1++)
{
if (labelHasFontTag(lblArray[intIndex1]))
restoreLabelFromTag(lblArray[intIndex1]);
}
}
//
--------------------------------------------------------------------
// Restore label font from tag
//
//
private static void restoreLabelFromTag(Label lblLabel)
{
lblLabel.Font = (Font)(lblLabel.Tag);
lblLabel.Refresh();
}
//
********************************************************************
//
* *
// * Sort: Generic Sort
Implementation *
//
* *
// * The sort class sorts generic arrays: an instance is
defined as *
// * sort<arrayType> where arrayType is the data type of each
array *
// * entry. The sort class also contains tools for
matching *
// * (comparing) two sorted arrays, and removing duplicates
from two *
// * sorted arrays. Three sort algorithms are provided:
bubble, *
// * interchange and quick sort (partition
exchange). *
//
* *
//
********************************************************************
public class sort<TYPofArray>
{
// ***** Constants *****
// --- Documentation
private const string CLASS_NAME = "sort";
private const string ABOUT_INFO =
"The sort class sorts generic arrays: an instance is "
+
"defined as sort<arrayType> where arrayType is the
data " +
"type of each array entry. The sort class also
contains " +
"tools for matching (comparing) two sorted arrays, and
" +
"removing duplicates from two sorted arrays. Three
sort " +
"algorithms are provided: bubble, interchange and
quick sort " +
"(partition exchange).";
// --- Inspection
private const string INSPECT_USABILITY =
"Object instance must be usable";
private const string INSPECT_ALGORITHM =
"Algorithm enumerator must be valid";
private const string INSPECT_DATATYPE =
"Datatype enumerator must be valid";
private const string INSPECT_TIMINGS =
"The timings structure, if not null, must pass its own
" +
"inspection";
// --- Testing
private const int MAX_TESTARRAY_SIZE = 100;
// ***** Static *****
private static int _INTsequence;
// ***** State *****
// --- Algorithm type
public enum ENUalgorithm
{
bubbleSort, interchangeSort, quickSort, unknown
}
// --- Known data types
public enum ENUknownDatatype
{
booleanDatatype,
byteDatatype,
shortDatatype,
integerDatatype,
longDatatype,
floatDatatype,
doubleDatatype,
stringDatatype,
otherDatatype,
unknown
}
private struct TYPstate
{
public bool booUsable;
public string strName;
public ENUalgorithm enuAlgorithmSelected;
public ENUknownDatatype enuDatatype;
public TYPtimings usrTimings;
public object OBJtag;
}
private TYPstate USRstate;
// ***** Events *****
// --- Compare event
public delegate void compareEventDelegate
(object objSender,
TYPofArray objComparand1,
TYPofArray objComparand2,
int intComparand1Index,
int intComparand2Index,
ref int intCompareResult);
public event compareEventDelegate compareEvent;
// --- Exchange event
public delegate void exchangeEventDelegate
(object objSender,
int intIndex1, int intIndex2);
public event exchangeEventDelegate exchangeEvent;
// --- Partition event
public delegate void partitionEventDelegate
(object objSender,
TYPofArray objPartitionValue,
int intPartitionIndex);
public event partitionEventDelegate partitionEvent;
// --- Sort starts event
public delegate void sortStartEventDelegate
(object objSender,
int intLeft, int intRight);
public event sortStartEventDelegate sortStartEvent;
// ***** Constructors
*****************************************
// --- Quicksort will be used, no timing info
public sort()
{
sort_(sort<TYPofArray>.ENUalgorithm.quickSort, false);
}
// --- Chooses algorithm, no timing info
public sort(ENUalgorithm enuNewAlgorithm)
{
sort_(enuNewAlgorithm, false);
}
// --- Chooses algorithm, timing info
public sort(ENUalgorithm enuNewAlgorithm,
bool booTimingInfo)
{
sort_(enuNewAlgorithm, booTimingInfo);
}
// --- Common logic
private void sort_(ENUalgorithm enuAlgorithm,
bool booTimingInfo)
{
USRstate.strName =
CLASS_NAME +
Interlocked.Increment(ref _INTsequence).ToString()
+
" " +
System.DateTime.Now;
if (!checkAlgorithm_(enuAlgorithm))
{
errorHandler_("Invalid sort algorithm",
"sort_()",
"Class instance is unusable");
return;
}
USRstate.enuAlgorithmSelected = enuAlgorithm;
USRstate.enuDatatype =
sort<TYPofArray>.ENUknownDatatype.unknown;
if (booTimingInfo)
USRstate.usrTimings = new TYPtimings(0, 0, 0);
else USRstate.usrTimings = new TYPtimings(false);
if (!USRstate.usrTimings.Usable) return;
USRstate.OBJtag = null;
USRstate.booUsable = true;
USRstate.booUsable = inspection_();
}
// ***** Public procedures
************************************
//
* *
// * May also contain private procedures that do work
on *
// * behalf of one public
procedure. *
//
* *
//
************************************************************
//
------------------------------------------------------------
// Return About information
//
//
public static string About
{
get { return ABOUT_INFO; }
}
//
------------------------------------------------------------
// Return average sort time information
//
//
public string AverageSortTimes
{
get
{
if (!checkUsability_("AverageSortTimes",
"Returning a null string"))
return "";
return USRstate.usrTimings.toString();
}
}
//
------------------------------------------------------------
// Dispose
//
//
public bool dispose()
{
if (!checkUsability_("dispose()", "No change made"))
return false;
USRstate.usrTimings.dispose();
return true;
}
//
------------------------------------------------------------
// Inspection
//
//
public bool inspect(ref string strReport)
{
strReport = "Inspection of " +
USRstate.strName + " " +
"at " + System.DateTime.Now;
bool booInspect = true;
if (utilities.inspectionAppend
(ref strReport,
INSPECT_USABILITY,
USRstate.booUsable,
ref booInspect))
{
utilities.inspectionAppend
(ref strReport,
INSPECT_ALGORITHM,
checkAlgorithm_(USRstate.enuAlgorithmSelected),
ref booInspect);
utilities.inspectionAppend
(ref strReport,
INSPECT_DATATYPE,
checkDatatype_(USRstate.enuDatatype),
ref booInspect);
string strSubreport = "";
utilities.inspectionAppend
(ref strReport,
INSPECT_TIMINGS,
USRstate.usrTimings.inspect(ref
strSubreport),
ref booInspect);
}
if (!booInspect) mkUnusable();
strReport = utilities.separateStrings
(strReport,
"Inspection " +
(booInspect ? "succeeded" : "failed"));
return booInspect;
}
//
------------------------------------------------------------
// Extend inspection report on behalf of inspect()
//
//
private void inspect_append_(ref string strReport,
string strNewInfo)
{
strReport = utilities.separateStrings
(strReport, strNewInfo);
}
//
------------------------------------------------------------
// Make class instance unusable
//
//
public bool mkUnusable()
{
if (!checkUsability_("mkUnusable()", "No change
made"))
return false;
USRstate.booUsable = false;
return true;
}
//
------------------------------------------------------------
// Return the class instance name
//
//
public string Name
{
get { return USRstate.strName; }
set
{
if (!checkUsability_("Name set", "No change
made"))
return;
USRstate.strName = value;
}
}
//
------------------------------------------------------------
// Sort the array
//
//
public bool sortArray(TYPofArray[] objArray)
{
return sortArray_(objArray, 0,
objArray.GetUpperBound(0));
}
// --- Sort array segment - check usability
private bool sortArray_(TYPofArray[] objArray,
int intLeft,
int intRight)
{
if (!checkUsability_("sortArray()",
"No sort performed: returning
false"))
return false;
return sortArray__(objArray, intLeft, intRight);
}
// --- Sort array segment (private)
private bool sortArray__(TYPofArray[] objArray,
int intLeft,
int intRight)
{
if (USRstate.usrTimings.Active)
{
USRstate.usrTimings.stopwatchStop();
USRstate.usrTimings.stopwatchReset();
USRstate.usrTimings.stopwatchStart();
}
switch (USRstate.enuAlgorithmSelected)
{
case sort<TYPofArray>.ENUalgorithm.bubbleSort:
{
sortArray__bubbleSort_(objArray,
intLeft,
intRight);
break;
}
case
sort<TYPofArray>.ENUalgorithm.interchangeSort:
{
sortArray__interchangeSort_(objArray,
intLeft,
intRight);
break;
}
case sort<TYPofArray>.ENUalgorithm.quickSort:
{
sortArray__quickSort_(objArray,
intLeft,
intRight);
break;
}
default:
{
return errorHandler_
("Unexpected case",
"sortArray__()",
"Class instance is unusable: " +
"returning false");
}
}
if (USRstate.usrTimings.Active)
{
USRstate.usrTimings.stopwatchStop();
USRstate.usrTimings.incrementJobs();
USRstate.usrTimings.increaseElements
(intRight - intLeft + 1);
USRstate.usrTimings.changeTime();
}
return true;
}
//
------------------------------------------------------------
// Sort array using bubbly wubbly sort
//
//
private bool sortArray__bubbleSort_(TYPofArray[] objArray,
int intLeft,
int intRight)
{
if (sortStartEvent != null)
sortStartEvent(this, intLeft, intRight);
int intIndex1;
int intIndex2;
bool booExchange = true;
while (booExchange)
{
booExchange = false;
for (intIndex1 = intLeft;
intIndex1 < intRight;
intIndex1++)
{
if (compareValues_
(objArray[intIndex1],
objArray[intIndex2 = intIndex1 + 1],
intIndex1, intIndex2)
>
0)
{
sortArray__exchangeValues_(objArray,
intIndex1,
intIndex2);
booExchange = true;
}
}
}
return true;
}
//
------------------------------------------------------------
// Exchange values on behalf of sortArray__()
//
//
private void sortArray__exchangeValues_
(TYPofArray[] objArray,
int intIndex1,
int intIndex2)
{
TYPofArray objExchange = objArray[intIndex1];
objArray[intIndex1] = objArray[intIndex2];
objArray[intIndex2] = objExchange;
if (exchangeEvent != null)
exchangeEvent(this, intIndex1, intIndex2);
}
//
------------------------------------------------------------
// Sort array using interchange
//
//
private bool sortArray__interchangeSort_(TYPofArray[]
objArray,
int intLeft,
int intRight)
{
if (sortStartEvent != null)
sortStartEvent(this, intLeft, intRight);
int intIndex1;
int intIndex2;
for (intIndex1 = intLeft;
intIndex1 < intRight;
intIndex1++)
for (intIndex2 = intIndex1 + 1;
intIndex2 <= intRight;
intIndex2++)
{
if (compareValues_
(objArray[intIndex1],
objArray[intIndex2],
intIndex1, intIndex2)
>
0)
{
sortArray__exchangeValues_(objArray,
intIndex1,
intIndex2);
}
}
return true;
}
//
------------------------------------------------------------
// Sort array using quickSort
//
//
private bool sortArray__quickSort_(TYPofArray[] objArray,
int intLeft,
int intRight)
{
if (sortStartEvent != null)
sortStartEvent(this, intLeft, intRight);
if (intRight > intLeft)
{
int intPivotNewIndex =
sortArray__quickSort_partition_
(objArray,
intLeft,
intRight,
intLeft);
if (partitionEvent != null)
partitionEvent(this,
objArray[intPivotNewIndex],
intPivotNewIndex);
sortArray__quickSort_(objArray,
intLeft,
intPivotNewIndex - 1);
sortArray__quickSort_(objArray,
intPivotNewIndex + 1,
intRight);
}
return true;
}
//
------------------------------------------------------------
// Partition array on behalf of sort()
//
//
// Pseudo-code (Wikipedia 2008):
//
// function partition(array, left, right, pivotIndex)
// pivotValue := array[pivotIndex]
// swap array[pivotIndex] and array[right] //
Move pivot to end
// storeIndex := left
// for i from left to right // left ≤ i <
right
// if array[i] ≤ pivotValue
// swap array[i] and array[storeIndex]
// storeIndex := storeIndex + 1
// swap array[storeIndex] and array[right] //
Move pivot to its final place
// return storeIndex
//
private int sortArray__quickSort_partition_
(TYPofArray[] objArray,
int intLeft,
int intRight,
int intPivotIndex)
{
TYPofArray objPivotValue = objArray[intPivotIndex];
sortArray__exchangeValues_(objArray,
intPivotIndex,
intRight);
int intStoreIndex = intLeft;
int intIndex1;
for (intIndex1 = intLeft;
intIndex1 < intRight;
intIndex1++)
{
if (compareValues_(objArray[intIndex1],
objPivotValue,
intIndex1,
intPivotIndex)
<
0)
{
sortArray__exchangeValues_(objArray,
intStoreIndex,
intIndex1);
intStoreIndex += 1;
}
}
sortArray__exchangeValues_(objArray,
intStoreIndex,
intRight);
return intStoreIndex;
}
//
------------------------------------------------------------
// Return and assign affiliated Tag
//
//
public object Tag
{
get
{
if (!checkUsability_("Tag get", "Returning null"))
return null;
return USRstate.OBJtag;
}
set
{
if (!checkUsability_("Tag set", "No change made"))
return;
USRstate.OBJtag = null;
}
}
//
------------------------------------------------------------
// Return usability
//
//
public bool Usable
{
get { return USRstate.booUsable; }
}
// ***** Private procedures
***********************************
//
------------------------------------------------------------
// Algorithm to string
//
//
private string algorithm2String_(ENUalgorithm enuAl)
{
string strName = "";
checkAlgorithm_(enuAl, ref strName);
return strName;
}
//
------------------------------------------------------------
// Check algorithm enum
//
//
private bool checkAlgorithm_
(sort<TYPofArray>.ENUalgorithm enuAl)
{
string strDummy = "";
return checkAlgorithm_(enuAl, ref strDummy);
}
private bool checkAlgorithm_
(sort<TYPofArray>.ENUalgorithm enuAl,
ref string strToString)
{
switch (enuAl)
{
case sort<TYPofArray>.ENUalgorithm.bubbleSort:
{
strToString = "bubbleSort";
return true;
}
case
sort<TYPofArray>.ENUalgorithm.interchangeSort:
{
strToString = "interchangeSort";
return true;
}
case sort<TYPofArray>.ENUalgorithm.quickSort:
{
strToString = "quickSort";
return true;
}
default:
{
strToString = "unknown";
return false;
}
}
}
//
------------------------------------------------------------
// Check data type enum
//
//
private bool checkDatatype_
(sort<TYPofArray>.ENUknownDatatype enuDT)
{
string strDummy = "";
return checkDatatype_(enuDT, ref strDummy);
}
private bool checkDatatype_
(sort<TYPofArray>.ENUknownDatatype enuDT,
ref string strToString)
{
switch (enuDT)
{
case
sort<TYPofArray>.ENUknownDatatype.booleanDatatype:
{ strToString = "booleanDatatype"; return
true; }
case
sort<TYPofArray>.ENUknownDatatype.byteDatatype:
{ strToString = "byteDatatype"; return true; }
case
sort<TYPofArray>.ENUknownDatatype.shortDatatype:
{ strToString = "shortDatatype"; return
true; }
case
sort<TYPofArray>.ENUknownDatatype.integerDatatype:
{ strToString = "integerDatatype"; return
true; }
case
sort<TYPofArray>.ENUknownDatatype.longDatatype:
{ strToString = "longDatatype"; return true; }
case
sort<TYPofArray>.ENUknownDatatype.floatDatatype:
{ strToString = "floatDatatype"; return
true; }
case
sort<TYPofArray>.ENUknownDatatype.doubleDatatype:
{ strToString = "doubleDatatype"; return
true; }
case
sort<TYPofArray>.ENUknownDatatype.stringDatatype:
{ strToString = "stringDatatype"; return
true; }
case sort<TYPofArray>.ENUknownDatatype.unknown:
{ strToString = "unknownDatatype"; return
true; }
default:
{ strToString = "invalidDatatype"; return
true; }
}
}
//
------------------------------------------------------------
// Check usability
//
//
private bool checkUsability_(string strProcedure,
string strAction)
{
if (USRstate.booUsable) return true;
return errorHandler_("Class instance is not usable",
strProcedure,
strAction);
}
//
------------------------------------------------------------
// Compare values
//
//
private int compareValues_
(TYPofArray objComparand1,
TYPofArray objComparand2,
int intIndex1,
int intIndex2)
{
// --- Use event
int intCompareResult = 0;
if (compareEvent != null)
compareEvent(this,
objComparand1,
objComparand2,
intIndex1,
intIndex2,
ref intCompareResult);
else
{
// --- Determine data type and if available use
this too
if (USRstate.enuDatatype ==
ENUknownDatatype.unknown
&&
((USRstate.enuDatatype
=
compareValues__determineDatatype_())
==
ENUknownDatatype.unknown)
||
USRstate.enuDatatype ==
ENUknownDatatype.otherDatatype)
{
errorHandler_("Compare event not provided, or
" +
"didn't complete: data type of "
+
"array cannot be determined",
"compareValues_",
"Marking class instance
unusable: " +
"returning 0");
return 0;
}
object objComparand1copy = objComparand1;
object objComparand2copy = objComparand2;
switch (USRstate.enuDatatype)
{
case ENUknownDatatype.booleanDatatype:
return (int)(objComparand1copy)
<
(int)(objComparand2copy)
?
-1
:
(int)(objComparand1copy)
>
(int)(objComparand2copy)
?
1
:
0;
case ENUknownDatatype.byteDatatype:
return (byte)(objComparand1copy)
<
(byte)(objComparand2copy)
?
-1
:
(byte)(objComparand1copy)
>
(byte)(objComparand2copy)
?
1 :
0;
case ENUknownDatatype.doubleDatatype:
return (double)(objComparand1copy)
<
(double)(objComparand2copy)
?
-1
:
(double)(objComparand1copy)
>
(double)(objComparand2copy)
?
1
:
0;
case ENUknownDatatype.integerDatatype:
return (int)(objComparand1copy)
<
(int)(objComparand2copy)
?
-1
:
(int)(objComparand1copy)
>
(int)(objComparand2copy)
?
1 :
0;
case ENUknownDatatype.longDatatype:
return (long)(objComparand1copy)
<
(long)(objComparand2copy)
?
-1
:
(long)(objComparand1copy)
>
(long)(objComparand2copy)
?
1
:
0;
case ENUknownDatatype.shortDatatype:
return (short)(objComparand1copy)
<
(short)(objComparand2copy)
?
-1
:
(short)(objComparand1copy)
>
(short)(objComparand2copy)
?
1 :
0;
case ENUknownDatatype.floatDatatype:
return (float)(objComparand1copy)
<
(float)(objComparand2copy)
?
-1
:
(float)(objComparand1copy)
>
(float)(objComparand2copy)
?
1
:
0;
case ENUknownDatatype.stringDatatype:
return ((string)
(objComparand1copy)).CompareTo
((string)(objComparand1copy));
default:
{
errorHandler_("Programming error",
"compareValues_()",
"Marking object
unusable: " +
"returning zero",
null);
return 0;
}
}
}
return intCompareResult;
}
//
------------------------------------------------------------
// Determine data type on behalf of compareValues_()
//
//
// The data type is determined in this way:
//
//
// * The default() method is used to tell if the
data
// type is one of the value types (bool, byte,
short,
// int, long, float, double or string). If the
data
// type defaults to null, we return our "other"
// data type.
//
// * Then, the ToString() of an instance's GetType
is
// used to find the name of the data type.
//
// * However, we don't trust this ToString()
completely.
// Instead, based on the ToString() GetType, we
make
// certain that the instance's value can be
assigned
// to this data type.
//
//
public ENUknownDatatype
compareValues__determineDatatype_()
{
TYPofArray objTest = default(TYPofArray);
if (objTest == null) return
ENUknownDatatype.otherDatatype;
string strGetType = objTest.GetType().ToString();
try
{
bool booTest = false;
if (strGetType == booTest.GetType().ToString())
{
booTest = (bool)(object)objTest;
return ENUknownDatatype.booleanDatatype;
}
byte bytTest = 0;
if (strGetType == bytTest.GetType().ToString())
{
bytTest = (byte)(object)objTest;
return ENUknownDatatype.byteDatatype;
}
short shrTest = 0;
if (strGetType == shrTest.GetType().ToString())
{
shrTest = (short)(object)objTest;
return ENUknownDatatype.shortDatatype;
}
int intTest = 0;
if (strGetType == intTest.GetType().ToString())
{
intTest = (int)(object)objTest;
return ENUknownDatatype.integerDatatype;
}
long lngTest = 0;
if (strGetType == lngTest.GetType().ToString())
{
lngTest = (long)(object)objTest;
return ENUknownDatatype.longDatatype;
}
float floTest = 0;
if (strGetType == floTest.GetType().ToString())
{
floTest = (float)(object)objTest;
return ENUknownDatatype.floatDatatype;
}
double dblTest = 0;
if (strGetType == dblTest.GetType().ToString())
{
dblTest = (Double)(object)objTest;
return ENUknownDatatype.doubleDatatype;
}
string strTest = "";
if (strGetType == strTest.GetType().ToString())
{
strTest = (string)(object)objTest;
return ENUknownDatatype.stringDatatype;
}
}
catch
{
}
return ENUknownDatatype.unknown;
}
//
------------------------------------------------------------
// Datatype to string
//
//
private string datatype2String_(ENUknownDatatype enuDT)
{
string strName = "";
checkDatatype_(enuDT, ref strName);
return strName;
}
//
------------------------------------------------------------
// Error handler
//
//
private bool errorHandler_(string strErrorMessage,
string strProcedure,
string strHelp)
{
return errorHandler_(strErrorMessage,
strProcedure,
strHelp,
null);
}
private bool errorHandler_(string strErrorMessage,
string strProcedure,
string strHelp,
Exception objException)
{
return utilities.errorHandler
(strErrorMessage,
CLASS_NAME,
strProcedure,
strHelp,
objException);
}
//
------------------------------------------------------------
// Internal inspection
//
//
private bool inspection_()
{
string strReport = "";
if (inspect(ref strReport)) return true;
return errorHandler_("Internal inspection not passed",
"inspection_()",
utilities.separateStrings
("Class instance is not usable",
strReport));
}
//
------------------------------------------------------------
// Make a Random object
//
//
private Random mkRandom_(bool booDeterministic)
{
try
{
if (booDeterministic)
return new Random(1);
else return new Random();
}
catch (System.Exception objException)
{
errorHandler_
("Cannot make randomizer",
"mkRandom_()",
"Returning false",
objException);
return null;
}
}
//
************************************************************
//
* *
// * TYPtimings Active structure for timing
measurement *
//
* *
//
************************************************************
private struct TYPtimings
{
// ***** Constants *****
// --- Documentation
private const string STRUCT_NAME =
"TYPtimings";
private const string ABOUT_INFO =
"Container for sort time results";
// --- Inspection
private const string INSPECT_USABILITY =
"Structure instance must be usable";
private const string INSPECT_RANGE =
"Total time, jobs and elements must be >= 0 or
-1";
private const string INSPECT_STOPWATCH =
"If no stopwatch exists, total time, jobs and " +
"elements must be zero";
// --- Misc
private const string UNUSABILITY_MESSAGE =
"Structure instance is not usable";
private const string INSUFFICIENT_INFORMATION =
"No timing information is available";
private const double OVERFLOW = -1;
// ***** State *****
private bool BOOusable;
private System.Diagnostics.Stopwatch OBJstopwatch;
private double DBLtotalTime;
private long LNGtotalElements;
private long LNGtotalJobs;
// ****** Constructors
************************************
// --- Create inactive instance with no stopwatch
public TYPtimings(bool booDummy)
{
BOOusable = false;
DBLtotalTime = 0;
LNGtotalElements = 0;
LNGtotalJobs = 0;
OBJstopwatch = null;
BOOusable = true;
BOOusable = inspection_();
}
// --- Create active instance with stopwatch: usually
// --- called using new TYPtimings(0, 0, 0)
public TYPtimings(double dblTotalTime,
long lngTotalElements,
long lngTotalJobs)
{
BOOusable = false;
DBLtotalTime = dblTotalTime;
LNGtotalElements = lngTotalElements;
LNGtotalJobs = lngTotalJobs;
OBJstopwatch = null;
try
{
OBJstopwatch = new
System.Diagnostics.Stopwatch();
}
catch (Exception objException)
{
utilities.errorHandler
("Cannot create stop watch",
STRUCT_NAME,
"TYPtimings()",
"Structure instance is unusable",
objException);
return;
}
BOOusable = true;
BOOusable = inspection_();
}
// ****** Public procedures
*******************************
//
--------------------------------------------------------
// Return information about this structure
//
//
public static string About
{
get { return ABOUT_INFO; }
}
//
--------------------------------------------------------
// Tell whether structure is active and can be used
for
// timing measurement
//
//
public bool Active
{
get
{
return Usable && OBJstopwatch != null;
}
}
//
--------------------------------------------------------
// Add stopwatch's elapsed time to sum
//
//
public bool changeTime()
{
if (!checkUsable_("incrementJobs()", "No change
made")
||
!Active
||
!DataAvailable)
return false;
try
{
double dblSave = DBLtotalTime;
DBLtotalTime +=
OBJstopwatch.Elapsed.TotalMilliseconds;
if (dblSave > DBLtotalTime)
{
indicateOverflow_(); return false;
}
return true;
}
catch
{
indicateOverflow_();
return false;
}
}
//
--------------------------------------------------------
// Return class name
//
//
public static string ClassName
{
get { return STRUCT_NAME; }
}
//
--------------------------------------------------------
// Tell caller whether data is available
//
//
public bool DataAvailable
{
get
{
return Usable && Active
&&
LNGtotalElements >= 1
&&
LNGtotalJobs >= 1
&&
DBLtotalTime >= 0;
}
}
//
--------------------------------------------------------
// Dispose struct instance
//
//
public bool dispose()
{
if (!checkUsable_("dispose()", "No change made"))
return false;
mkUnusable_();
if (OBJstopwatch != null)
OBJstopwatch = null;
return true;
}
//
--------------------------------------------------------
// Increase sort element count
//
//
public bool increaseElements(long lngMore)
{
if (!checkUsable_("increaseElements()", "No change
made")
||
!DataAvailable)
return false;
try
{
long lngSave = LNGtotalElements;
LNGtotalElements += lngMore;
if (lngSave >= LNGtotalElements)
{
indicateOverflow_(); return false;
}
return true;
}
catch
{
indicateOverflow_();
return false;
}
}
//
--------------------------------------------------------
// Increase job count by one
//
//
public bool incrementJobs()
{
if (!checkUsable_("incrementJobs()", "No change
made")
||
!DataAvailable)
return false;
try
{
long lngSave = LNGtotalJobs;
LNGtotalJobs++;
if (lngSave >= LNGtotalJobs)
{
indicateOverflow_(); return false;
}
return true;
}
catch
{
indicateOverflow_();
return false;
}
}
//
--------------------------------------------------------
// Inspect struct instance
//
//
public bool inspect(ref string strReport)
{
bool booInspection = true;
if (utilities.inspectionAppend
(ref strReport,
INSPECT_USABILITY,
BOOusable,
ref booInspection))
{
utilities.inspectionAppend
(ref strReport,
INSPECT_RANGE,
LNGtotalElements >= 0
&&
LNGtotalJobs >= 0
&&
DBLtotalTime >= 0
||
LNGtotalElements == OVERFLOW
&&
LNGtotalJobs == OVERFLOW
&&
DBLtotalTime == OVERFLOW,
ref booInspection);
utilities.inspectionAppend
(ref strReport,
INSPECT_STOPWATCH,
OBJstopwatch != null
||
LNGtotalJobs == 0
&&
DBLtotalTime == 0
&&
DBLtotalTime == 0,
ref booInspection);
}
if (!booInspection) mkUnusable_();
return booInspection;
}
//
--------------------------------------------------------
// Reset the stop watch
//
//
public bool stopwatchReset()
{
if (!checkUsable_("stopwatchReset()",
"No change made")
||
!checkActive_("stopwatchReset()",
"No change made")) return false;
if (OBJstopwatch.IsRunning) OBJstopwatch.Stop();
OBJstopwatch.Reset(); return true;
}
//
--------------------------------------------------------
// Start the stop watch
//
//
public bool stopwatchStart()
{
if (!checkUsable_("stopwatchStart()", "No change
made")
||
!checkActive_("stopwatchStart()", "No change
made"))
return false;
if (OBJstopwatch.IsRunning)
return (utilities.errorHandler
("Stopwatch is running already",
CLASS_NAME,
"stopwatchStart()",
"No change made; returning false",
null));
OBJstopwatch.Start(); return true;
}
//
--------------------------------------------------------
// Stop the stop watch
//
//
public bool stopwatchStop()
{
if (!checkUsable_("stopwatchStop()", "No change
made")
||
!checkActive_("stopwatchStop()", "No change
made"))
return false;
if (!OBJstopwatch.IsRunning)
return (utilities.errorHandler
("Stopwatch is not running",
CLASS_NAME,
"stopwatchStop()",
"No change made; returning false",
null));
OBJstopwatch.Stop(); return true;
}
//
--------------------------------------------------------
// Return stopwatch value (milliseconds as a real
number)
//
//
public double StopwatchValue
{
get
{
if (!checkUsable_("StopwatchValue get",
"No change made: returning
zero")
||
!checkActive_("StopwatchValue get",
"No change made: returning
zero"))
return 0;
if (!OBJstopwatch.IsRunning)
{
utilities.errorHandler
("Stopwatch is not running",
CLASS_NAME,
"stopwatchValue()",
"Returning 0",
null);
return 0;
}
return OBJstopwatch.Elapsed.TotalMilliseconds;
}
}
//
--------------------------------------------------------
// Convert times to string
//
//
public string toString()
{
if (!checkUsable_("", ""))
return UNUSABILITY_MESSAGE;
if (!Active || !DataAvailable)
return INSUFFICIENT_INFORMATION;
return "Average time (milliseconds) per sort job:
" +
time2String_(DBLtotalTime /
(double)LNGtotalJobs) +
Environment.NewLine +
"Average time (milliseconds) " +
"per sorted element: " +
time2String_(DBLtotalTime /
(double)LNGtotalElements);
}
//
--------------------------------------------------------
// Tell caller if structure instance is usable
//
//
public bool Usable
{
get { return BOOusable; }
}
// ***** Private procedures
*******************************
//
--------------------------------------------------------
// Make sure structure instance is "active" and has a
// timer
//
//
private bool checkActive_(string strProcedure,
string strHelp)
{
if (Active) return true;
return utilities.errorHandler
("Structure instance is not active",
STRUCT_NAME,
strProcedure,
strHelp,
null);
}
//
--------------------------------------------------------
// Make sure structure instance is "usable"
//
//
private bool checkUsable_(string strProcedure,
string strHelp)
{
if (BOOusable) return true;
return utilities.errorHandler
("Structure instance is not usable",
STRUCT_NAME,
strProcedure,
strHelp,
null);
}
//
--------------------------------------------------------
// Set the overflow indicator values
//
//
private void indicateOverflow_()
{
DBLtotalTime = OVERFLOW;
LNGtotalElements = (long)OVERFLOW;
LNGtotalJobs = (long)OVERFLOW;
}
//
--------------------------------------------------------
// Internal inspection
//
//
private bool inspection_()
{
string strReport = "";
if (inspect(ref strReport)) return true;
return utilities.errorHandler
("Structure has failed an internal
inspection",
STRUCT_NAME,
"inspection_()",
"Structure instance is unusable",
null);
}
//
--------------------------------------------------------
// Make structure instance unusable
//
//
private bool mkUnusable_()
{
BOOusable = false; return true;
}
//
--------------------------------------------------------
// Convert time to string
//
//
private string time2String_(double dblTime)
{
if (dblTime < 10e-10) return "near zero";
return dblTime.ToString();
}
}
}
//
****************************************************************
//
* *
// *
utilities *
//
* *
//
****************************************************************
private static class utilities
{
//
------------------------------------------------------------
// Error handler
//
//
public static bool errorHandler
(string strMessage,
string strClassOrObject,
string strProcedure,
string strHelp)
{
return errorHandler(strMessage,
strClassOrObject,
strProcedure,
strHelp,
null,
false);
}
public static bool errorHandler
(string strMessage,
string strClassOrObject,
string strProcedure,
string strHelp,
Exception objException)
{
return errorHandler(strMessage,
strClassOrObject,
strProcedure,
strHelp,
objException,
false);
}
public static bool errorHandler
(string strMessage,
string strClassOrObject,
string strProcedure,
string strHelp,
Exception objException,
bool booFinal)
{
string strFull =
separateStrings
(separateStrings
("Error in " +
strClassOrObject +
"." +
strProcedure + ": ",
strMessage),
separateStrings
(strHelp,
objException == null
?
""
:
objException.ToString()));
if (booFinal)
MessageBox.Show(strFull);
else
{
Exception objInnerException = null;
try
{
objInnerException =
new Exception(strFull);
}
catch
{
MessageBox.Show
(separateStrings
("The following exception " +
"cannot be created: " +
"terminating",
strFull));
Application.Exit();
}
throw objInnerException;
}
return false;
}
//
----------------------------------------------------------------------
// Inspection and test append
//
//
public static bool inspectionAppend
(ref string strReport,
string strRule,
bool booRuleResult,
ref bool booInspection)
{
return inspectionAppend(ref strReport,
strRule,
booRuleResult,
ref booInspection,
"");
}
public static bool inspectionAppend
(ref string strReport,
string strRule,
bool booRuleResult,
ref bool booInspection,
string strComments)
{
strReport = separateStrings
(separateStrings
(strReport,
strRule + ": " +
(booRuleResult ? "OK" : "Failed")),
strComments);
booInspection = booRuleResult && booInspection;
return booRuleResult;
}
//
--------------------------------------------------------
// Separate two strings
//
//
// --- Separator defaults to one newline (if neither
string
// --- contains a newline) or two newlines
public static string separateStrings(string strString1,
string strString2)
{
return separateStrings
(strString1,
strString2,
Environment.NewLine +
(strString1.IndexOf(Environment.NewLine) == -1
&&
strString1.IndexOf(Environment.NewLine) == -1
?
""
:
Environment.NewLine));
}
// --- Separator is specified
public static string separateStrings(string strString1,
string strString2,
string strSeparator)
{
return strString1 +
(strString1.Trim() != ""
&&
strString2.Trim() != ""
?
strSeparator
:
"") +
strString2;
}
}
//
************************************************************
// *
*
// * windowsUtilities
*
// *
*
//
************************************************************
private static class windowsUtilities
{
//
--------------------------------------------------------
// Make button
//
//
public static Button mkButton(string strText,
int intLeft, int intTop,
int intWidth, int intHeight)
{
try
{
Button cmdNew = new Button();
cmdNew.Left = intLeft; cmdNew.Top = intTop;
cmdNew.Width = intWidth; cmdNew.Height =
intHeight;
cmdNew.Refresh();
return cmdNew;
}
catch (Exception objException)
{
utilities.errorHandler("Can't make button",
"windowsUtilities",
"mkButton",
"Returning null",
objException);
return null;
}
}
//
--------------------------------------------------------
// Return the screen height
//
//
// This method returns the height of the primary screen
as
// its function value (see also screenWidth and
// screenSize). It will return -1 for the height if there
// is no primary screen. It will return -2 for the height
// if for some sillyassed reason, there are multiple
// primary screens.
//
// The width will be the working width. In particular,
// note that the height will not include the space
occupied
// by a visible Task bar.
//
//
public static int screenHeight()
{
int intHeight = 0;
int intWidth = 0;
screenSize(ref intWidth, ref intHeight);
return intHeight;
}
//
--------------------------------------------------------
// Return the screen size
//
//
// This method returns the width and the height of the
// primary screen in reference parameters (see also
// screenWidth and screenHeight). It will return -1 for
// width and for height if there is no primary screen. It
// will return -2 for width and for height if for some
// sillyassed reason, there are multiple primary screens.
//
// Both the width and the height are the working width
// and height. In particular, note that the height will
not
// include the space occupied by a visible Task bar.
//
//
public static bool screenSize(ref int intWidth,
ref int intHeight)
{
int intIndex1;
System.Windows.Forms.Screen[] objScreens =
System.Windows.Forms.Screen.AllScreens;
intWidth = -1; intHeight = -1;
for (intIndex1 = 0;
intIndex1 <= objScreens.GetUpperBound(0);
intIndex1++)
{
if (objScreens[intIndex1].Primary)
{
if (intWidth == -1 && intHeight == -1)
{
intWidth =
objScreens[intIndex1].WorkingArea.Width;
intHeight =
objScreens[intIndex1].WorkingArea.Height;
}
else
{ intWidth = -2; intHeight = -2; }
}
}
switch (intWidth)
{
case -1:
{
return utilities.errorHandler
("Cannot find the screen
dimensions",
"windowsUtilities",
"screenSize()",
"Returning screen sizes as -1: "
+
"function return is false");
}
case -2:
{
return utilities.errorHandler
("Multiple screen dimensions
found",
"windowsUtilities",
"screenSize()",
"Returning screen sizes as -2: "
+
"function return is false");
}
default:
{
return true;
}
}
}
//
--------------------------------------------------------
// Return the screen height
//
//
// This method returns the height of the primary screen
as
// its function value (see also screenWidth and
// screenSize). It will return -1 for the height if there
// is no primary screen. It will return -2 for the height
// if for some sillyassed reason, there are multiple
// primary screens.
//
// The width will be the working width. In particular,
// note that the height will not include the space
occupied
// by a visible Task bar.
//
//
public static int screenWidth()
{
int intHeight = 0;
int intWidth = 0;
screenSize(ref intWidth, ref intHeight);
return intWidth;
}
}
}
}
.
- Follow-Ups:
- Re: C Sharp sorting considered superior to C by an order of magnitude
- From: Josh Sebastian
- Re: C Sharp sorting considered superior to C by an order of magnitude
- From: Willem
- Re: C Sharp sorting considered superior to C by an order of magnitude
- Prev by Date: Re: C, for loops and optimisations
- Next by Date: Re: strlen(), K+1: clarification
- Previous by thread: I need to know the CPU Load with C++
- Next by thread: Re: C Sharp sorting considered superior to C by an order of magnitude
- Index(es):