Calculator
Extensible stack-based calculator primarily in library form
BinaryMathOperator.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2013, Komodo Does Inc
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6 
7 - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 - Neither the name of the Komodo Does Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 */
13 
14 #include <memory>
15 #include <functional>
16 #include <string>
17 #include <vector>
18 #include <map>
19 
20 #include "math.h"
21 
22 #include "BinaryMathOperator.h"
23 #include "Number.h"
24 #include "Stack.h"
25 #include "Error.h"
26 
27 namespace {
28  using namespace Calculator;
29 
30  /*
31  * This is a whole lot to just use one array of ops to get math functions and
32  * such....
33  *
34  * I wouldn't do it again unless there was a really long list....
35  */
36  class OpInfo {
37  public:
38  typedef std::function<float (float, float)> Function;
39 
40  OpInfo() {
41  }
42 
43  OpInfo(BinaryMathOperator::Operation theOp, const std::string& theSymbol, Function theFunction)
44  : op(theOp), symbol(theSymbol), function(theFunction)
45  {
46  }
47 
48  BinaryMathOperator::Operation getOp() const {
49  return op;
50  }
51 
52  std::string getSymbol() const {
53  return symbol;
54  }
55 
56  Function getFunction() const {
57  return function;
58  }
59 
60  private:
62  std::string symbol;
63  Function function;
64  };
65 
66  class OpInfoMap {
67  private:
68  typedef std::map<std::string, OpInfo> OpInfoBySymbol;
69  typedef std::map<BinaryMathOperator::Operation, OpInfo> OpInfoByOp;
70 
71  public:
72  OpInfoMap() {
73  const OpInfo data[] = {
74  OpInfo(BinaryMathOperator::Operation::ADD, "+", [](float a, float b)->float { return a + b; }),
75  OpInfo(BinaryMathOperator::Operation::SUBTRACT, "-", [](float a, float b)->float { return a - b; }),
76  OpInfo(BinaryMathOperator::Operation::MULTIPLY, "*", [](float a, float b)->float { return a * b; }),
77  OpInfo(BinaryMathOperator::Operation::DIVIDE, "/", [](float a, float b)->float { return a / b; }),
78  OpInfo(BinaryMathOperator::Operation::EXPONENT, "^", [](float a, float b)->float { return pow(a, b); })
79  };
80 
81  for(OpInfo info : data) {
82  bySymbol[info.getSymbol()] = info;
83  byOp[info.getOp()] = info;
84  }
85  }
86 
87  const OpInfo* operator[](std::string symbol) const {
88  OpInfoBySymbol::const_iterator found = bySymbol.find(symbol);
89  if(bySymbol.end() == found) {
90  return nullptr;
91  }
92  return &found->second;
93  }
94 
95  const OpInfo* operator[](BinaryMathOperator::Operation op) const {
96  OpInfoByOp::const_iterator found = byOp.find(op);
97  if(byOp.end() == found) {
98  return nullptr;
99  }
100  return &found->second;
101  }
102 
103  private:
104  OpInfoBySymbol bySymbol;
105  OpInfoByOp byOp;
106  };
107 
108  static const OpInfoMap opInfoMap;
109 }
110 
111 namespace Calculator {
112 
114  return Ptr(new BinaryMathOperator(op));
115  }
116 
118  }
119 
121  :op(operation)
122  {
123  }
124 
126  Number::Ptr first;
127  Number::Ptr second;
128  StackIterator iter = stack.begin();
129  iter >> first >> second;
130  // Defer stack.popAfter() until after evaluation
131 
132  if(!iter) {
133  return iter.getResult();
134  }
135 
136  // Do the math
137  const OpInfo* info = opInfoMap[op];
138  if(nullptr == info) {
139  // Internal error.... Not sure what to do.
140  return Result({"Internal Error: Missing BinaryMathOperator."});
141  }
142 
143  stack.popAfter(iter);
144  Number::Ptr item = Number::create(info->getFunction()(first->getValue(), second->getValue()));
145  (*item)(stack, item);
146 
147  return Result({Error::Ok});
148  }
149 
151  }
152 
153  std::string BinaryMathCreator::getHelp() const {
154  return "One op of: +-*/^ -- Replace the top and second items with top op second.\n\t^ is exponent.";
155  }
156 
158  const OpInfo* info = opInfoMap[str];
159  if(nullptr != info) {
160  return BinaryMathOperator::create(info->getOp());
161  } else {
162  return StackOperator::Ptr();
163  }
164  }
165 
166 } // namespace Calculator
virtual std::string getHelp() const
virtual StackOperator::Ptr create(const std::string &str)
@ MULTIPLY
Multiply the two values.
@ SUBTRACT
Subtract the two values.
@ EXPONENT
Raise top to the exponent second.
BinaryMathOperator(Operation op)
Create to perform operation.
std::shared_ptr< BinaryMathOperator > Ptr
static BinaryMathOperator::Ptr create(Operation op)
Create to perform operation.
virtual Result operator()(Stack &stack, StackOperator::Ptr ofThis)
Execute this operator on stack.
std::shared_ptr< Number > Ptr
Definition: Number.h:33
static Number::Ptr create(float theValue)
Create with theValue to represent.
Definition: Number.cpp:34
Collection of Result information for an operation.
Definition: Result.h:30
Stack of values to process from.
Definition: Stack.h:208
StackIterator begin()
Definition: Stack.cpp:221
void popAfter(StackIterator &iter)
Pop all items after iter on the Stack.
Definition: Stack.cpp:233
Iterator over a Stack from top to bottom.
Definition: Stack.h:35
const Result & getResult() const
Definition: Stack.cpp:150
std::shared_ptr< StackOperator > Ptr
Definition: StackOperator.h:31
const std::string Ok
Operation was successful.
Definition: Error.h:23
Container of Calculator resources.