Figure 3 CPrimeCalculator
Prime.h
#pragma once
#include <vector>
#include <list>
using namespace std;
/////////////////
// Interface for prime events. Not an interface in the .NET or COM sense,
// just an ordinary old abstract base class. Clients that handle prime
// events must derive from this and implement the virtual functions.
//
class IPrimeEvents {
protected:
IPrimeEvents() { }
virtual ~IPrimeEvents() { };
public:
virtual void OnProgress(UINT nPrimes) = 0;
virtual void OnDone() = 0;
};
// List (vector) of prime numbers.
typedef vector<UINT> PRIMELIST;
//////////////////////////////////////////////////////////////////
// Class to calculate 1st n prime numbers.
//
class CPrimeCalculator {
protected:
list<IPrimeEvents*> m_clients; // list of client objects to notify
PRIMELIST m_primes; // list (vector) of primes numbers found
// Helpers
BOOL IsPrime(UINT p); // is prime?
void AddPrime(UINT p) // add prime to list
{
m_primes.push_back(p);
}
// Raise events
void NotifyProgress(UINT nFound);
void NotifyDone();
public:
CPrimeCalculator() { }
~CPrimeCalculator() { }
// Find 1st n prime numbers.
UINT FindPrimes(UINT n);
// Get number of primes found so far.
UINT GetNumberOfPrimes() {
return (UINT)m_primes.size();
}
// Get all the primes found.
const PRIMELIST GetPrimes() {
return m_primes;
}
// Register client to receive events
void Register(IPrimeEvents* client)
{
m_clients.push_back(client);
}
// Unregister client from receiving events.
void Unregister(IPrimeEvents* client)
{
m_clients.remove(client);
}
};
Prime.cpp
#include "StdAfx.h"
#include "Prime.h"
const NOTIFYINCR = 100; // notify every 100 tries
const FIRSTPRIME = 2; // important!
//////////////////
// Find 1st n prime numbers.
//
UINT CPrimeCalculator::FindPrimes(UINT nFind)
{
m_primes.reserve(nFind);
for (UINT p=FIRSTPRIME; GetNumberOfPrimes()<nFind; p++) {
if (IsPrime(p)) { // if prime:
AddPrime(p);
}
if (p % NOTIFYINCR == 0) {
// report progress by raising event
NotifyProgress(GetNumberOfPrimes());
Sleep(30); // simulate work; otherwise too fast!
}
}
NotifyDone();
return GetNumberOfPrimes();
}
//////////////////
// Helper fn to test if number p is prime:
// Try dividing by all primes found so far, up to SQRT(p).
//
BOOL CPrimeCalculator::IsPrime(UINT p)
{
PRIMELIST::iterator it;
for (it=m_primes.begin(); it!=m_primes.end(); it++) {
UINT factor = *it;
if (p%factor == 0) { // if divisible:
return FALSE; // ..it's not prime
}
if (factor*factor > p) // if no more primes to try:
return TRUE; // ..number must be prime
}
// Should only get here when p==2 (list is empty).
ASSERT(p==2);
return TRUE;
}
//////////////////
// Notify clients of progress so far.
//
void CPrimeCalculator::NotifyProgress(UINT nFound)
{
list<IPrimeEvents*>::iterator it;
for (it=m_clients.begin(); it!=m_clients.end(); it++) {
(*it)->OnProgress(nFound);
}
}
//////////////////
// Notify clients I'm done.
//
void CPrimeCalculator::NotifyDone()
{
list<IPrimeEvents*>::iterator it;
for (it=m_clients.begin(); it!=m_clients.end(); it++) {
(*it)->OnDone();
}
}
Figure 4 PrimeCalc.cpp
#include "stdafx.h"
#include "StatLink.h"
#include "resource.h"
#include "Prime.h"
#include "TraceWin.h"
const NFIND = 1000; // find first 1000 primes
//////////////////
// This class displays IPrimeEvents in the diagnostic (TRACE) stream. Used
// to show that multiple objects can register for the same event stream.
//
class CTracePrimeEvents : public IPrimeEvents
{
public:
void OnProgress(UINT nPrimes)
{
UNREFERENCED_PARAMETER(nPrimes);
TRACE(_T(" PrimeCalc: Found %d primes.\n"), nPrimes);
}
virtual void OnDone()
{
TRACE(_T(" PrimeCalc: Done\n"));
}
};
//////////////////
// Main dialog: implements IPrimveEvents to handle events from
// CPrimeCalculator.
//
class CMyDlg : public CDialog, public IPrimeEvents {
protected:
.
.
CEdit m_wndFeedback;
// IPrimeEvents handlers
void OnProgress(UINT nPrimes);
void OnDone();
// message handler
void CMyDlg::OnCompute()
};
//////////////////
// User pressed "Compute" button.
//
void CMyDlg::OnCompute()
{
CWaitCursor wc; // display wait cursor
m_wndFeedback.SetWindowText(_T("Calculating..."));
// create prime calculator and hook events
CPrimeCalculator pc; // Prime calculator
CTracePrimeEvents tn; // TRACE notifier
pc.Register(this); // register myself for events
pc.Register(&tn); // .. and trace notifier too
pc.FindPrimes(NFIND); // find prime numbers
// Build message showing prime numbers.
CString msg,temp;
int any = 0;
PRIMELIST primes = pc.GetPrimes();
PRIMELIST::iterator it;
for (it=primes.begin(); it!=primes.end(); it++) {
UINT p = *it;
if (any)
msg += _T(", ");
else
any++;
temp.Format(_T("%d"),p);
msg += temp;
}
// show results in feedback window
m_wndFeedback.SetWindowText(msg);
}
//////////////////
// Event handler: Show progress.
//
void CMyDlg::OnProgress(UINT nPrimes)
{
CString s;
s.Format(_T(«Found %d primes so far...»), nPrimes);
m_wndFeedback.SetWindowText(s);
m_wndFeedback.UpdateWindow();
}
//////////////////
// Event handler: Beep when done.
//
void CMyDlg::OnDone() {
MessageBeep(0);
}