Rosettas‎ > ‎

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;
   }
}