C++
Rosetta.h
// Copyright (c) 2007 Art & Logic, Inc. All Rights Reserved.
// $Id: Rosetta.h,v 1.1 2008/01/15 21:05:14 bporter Exp $
// Above: [sf02], [sf03]
// a note on the stuff inside the square brackets:
// Each of the codes inside brackets is a reference to the rule(s) in the
// Style Guide that's being illustrated, as follows:
// [sf##] - StyleGuide/SourceFiles
// [cas##] - StyleGuide/ClassesAndStructures
// [nr##] - StyleGuide/NamingRules
// [cg##] - StyleGuide/Commenting
// [fmt##] - StyleGuide/Formatting
// Throughout: [fmt01]; all indentation done with space characters (0x20),
// three spaces per logical tab stop.
// [nr21] C/C++ guard to prevent recursive inclusion of header files
#ifndef h_Rosetta
#define h_Rosetta
// [sf05]
#include "AlTypes.h"
#include <fstream>
#include <string>
// [nr25] the 'q' prefix indicates that we are controlling conditional
// compilation
#define qVerbose
// [sf07], only one class declared/defined in this source file.
// [cg02], comments useful to programmers who will use (but not necessarily
// maintain) this class are separated out into the header file, not in the
// implementation file.
/**
* \class ARosetta
* \brief Simple, but meaningless class to demonstrate Art+Logic programming
* style conventions as they are applied to the various programming languages
* we use. In several places, you're asked to imagine a block of useful code
* to avoid distracting you from the issues of formatting (etc) that are being
* demonstrated.
*
* As you've already seen above, the thing about to be shown in this file is
* called out in comments using the A+L-style markup '!!!'
*/
// [nr11], [nr18] class names prefixed with "A"
class ARosetta
{
// [cas01] public member functions/methods listed first
public:
// [nr08] new non-class types (enumerations, data structures, etc) are
// named with MixedCase and no special prefix
enum EnumName
{
// [nr23] identifiers specifying constants for the program are always
// prefixed with a lowercase 'k'.
kSomeConstant = 50,
kSomeOtherConstant = 100
};
/**
* Construct and initialize the Rosetta object.
* \param fileName The file to use as our data source
*/
ARosetta(const std::string& fileName);
/**
* Destroy the Rosetta object, performing any needed cleanup.
*/
virtual ~ARosetta();
/**
* [nr07] Member functions are named using CamelCase, with a leading upper case
* letter.
*/
virtual bool MemberFunctionWithMultipleWords();
/**
* !!! Here's how we handle very long lines (i.e., longer than 79
* characters)
*/
bool LongLineWrapping();
/**
* !!! Loop formatting
*/
void Loops();
// [cas01] Protected member functions declared after public
protected:
/**
* [nr03] parameters passed to functions are named using lowerCamelCase
*/
virtual bool Test(SInt32 firstVal, SInt32 secondVal);
// [cas01] Private member function declared after protected
private:
/**
* Useful function to process something or other.
*/
void Process(SInt32 val);
/**
* Demonstrating the formatting of a switch statement.
*/
void Decide(UInt8 midiEventType);
// [cas02] member variables declared in the same order: public
// (avoid in most languages), protected, private.
public:
protected:
private:
// [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed
// by an uppercase letter.
std::string fFilename;
// [fmt28] -- when declaring pointer variables, attach the '*' to the
// typename, not the variable name.
std::ifstream* fInputFile;
SInt32 fProcessResult;
};
#endif
Rosetta.cpp
// Copyright (c) 2008 Art & Logic, Inc. All Rights Reserved.
// $Id: Rosetta.cpp,v 1.4 2008/01/21 18:22:22 dgrant Exp $
// Above: [sf02], [sf03]
// a note on the stuff inside the square brackets:
// Each of the codes inside brackets is a reference to the rule(s) in the
// Style Guide that's being illustrated, as follows:
// [sf##] - StyleGuide/SourceFiles
// [cas##] - StyleGuide/ClassesAndStructures
// [nr##] - StyleGuide/NamingRules
// [cg##] - StyleGuide/Commenting
// [fmt##] - StyleGuide/Formatting
// Throughout: [fmt01]; all indentation done with space characters (0x20),
// three spaces per logical tab stop.
#include "Rosetta.h"
ARosetta::ARosetta(std::string& fileName)
: fFilename(fileName),
fInputFile(NULL),
fProcessResult(0)
{
fInputFile = new std::ifstream(fFilename);
}
ARosetta::~ARosetta()
{
delete fInputFile;
fInputFile = NULL;
}
bool ARosetta::MemberFunctionWithMultipleWords()
{
bool ok = true;
// [fmt08] -- formatting of a for() loop.
for (SInt32 i = 0; i < kSomeConstant; ++i)
{
for (SInt32 j = 0; j < kSomeOtherConstant; ++j)
{
// [fmt02] -- preprocessor directives go in column zero.
#ifdef qVerbose
std::clog << "testing: " << i << ", " << j << std::endl;
#endif
// [nr07] -- Calls to member functions of the current object are
// made through an explicit this-> pointer.
ok = this->Test(i, j);
if (!ok)
{
std::cerr << "Fatal error testing: " << i << ", " << j << std::endl;
goto CleanUp;
}
}
}
return true;
// [fmt02] -- labels used as the target of a goto are placed in column zero.
CleanUp:
// cleanup code here...
return false;
}
bool ARosetta::LongLineWrapping()
{
// [fmt03] -- source lines should be less than 80 characters long.
// [fmt04] -- break lines at the most logical point
// 1 2 3 4 5 6 7
//34567890123456789012345678901234567890123456789012345678901234567890123456789
retval = FunctionWithManyArguments(longArgumentName1, longArgumentName2,
longArgumentName3, longArgumentName4);
// alternative format #1
retval = FunctionWithManyArguments(longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4);
// alternative format #2
retval = FunctionWithManyArguments(
longArgumentName1,
longArgumentName2,
longArgumentName3,
longArgumentName4);
// [fmt05] -- prefer to break after a comma
retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin(),
x.TopMargin() + x.BottomMargin() - 1);
// [fmt05] -- if that's not possible, break after an operator
retval = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin() +
anObject.HorizontalPadding(), x.TopMargin() + x.BottomMargin() - 1);
}
void ARosetta::Loops()
{
// [fmt08] -- for() loop; note the pre-incremented form of the loop control
for (int i = 0; i < kSomeConstant; ++i)
{
// loop code here...
}
// [fmt09]
while (someBoolean)
{
// useful code...
}
// [fmt09] -- while loop with an empty body makes the emptiness explicit
while (this->SomeFuncReturningBool())
{
// intentionally empty...
}
// [fmt10] -- do/while loop.
// [fmt18] -- exception to the bracing rule saying that braces should
// always be on a line by themselves
do
{
// loop code here..
} while (someBoolean);
}
bool ARosetta::Test(SInt32 firstVal, SInt32 secondVal)
{
bool retval = true;
// [fmt07] -- if/else formatting
if (firstVal < secondVal)
{
// [cg06] -- use '$$$' as a marker to indicate a request that the
// following block of code be reviewed before a change is considered
// complete
// $$$ before
// this->Process(secondVal);
// $$$ after
// Shouldn't this be processing the first value in this case?
this->Process(firstVal);
// $$$ end
}
else if (secondVal > kSomeConstant)
{
this->Process(secondVal);
}
else
{
// [fmt18] -- use curly braces even in cases where the language doesn't
// require it to prevent maintenance errors.
retval = false;
}
return retval;
}
void ARosetta::Process(SInt32 val)
{
// [cg05] -- use '!!!' as a marker to indicate a section of code that
// requires attention
// !!!... removing old hardcoded value
// fProcessResult = 131;
// ...!!!
SInt32 result = val;
while (--val)
{
result *= val;
}
fProcessResult = result;
}
void ARosetta::Decide(UInt8 midiEventType)
{
// [fmt11] -- switch/case formatting.
switch (midiEventType)
{
// comments precede the case
case kNoteOn:
this->NoteOn(now);
if (duration > 0)
{
this->NoteOff(now + duration);
}
break;
case kNoteOff:
this->NoteOff(now);
break;
case kPolyAfter:
after = channelValue;
// [fmt35] include, but comment out the break when falling through intentionally.
// break;
case kChannelAfter:
this->AfterTouch(after);
break;
// [fmt36] no need to include a commented out break when falling through an empty case
case kPitchbend:
// blank line...
// [fmt12] -- switch statements should always have a default case.
default:
ASSERT(false);
this->LogError("Unsupported event type!");
break;
}
}