1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "checked_adder.h" 18 19 #include <climits> 20 #include <iostream> 21 22 class CheckedAdder : public Adder { 23 private: 24 bool add_overflows(int x, int y) { 25 if (y > x) 26 std::swap(x, y); 27 // Now y <= x. 28 const int half_max = INT_MAX / 2; 29 const int half_min = INT_MIN / 2; 30 if (x > half_max) { 31 // We can't have negative overflow, but might have positive overflow. 32 if (y > half_max) 33 return true; 34 if (y <= 0) 35 return false; 36 // x <= INT_MAX && y <= half_max, 37 // so: x + y <= INT_MAX + half_max 38 // so: x - half_max + y <= INT_MAX 39 // so: (x - half_max + y) doesn't overflow. 40 // (x + y) > INT_MAX iff (x - half_max + y) > (INT_MAX - half_max) 41 return (x - half_max + y) > (INT_MAX - half_max); 42 } 43 // y <= x <= half_max, can't have positive overflow. 44 if (y < half_min) { 45 // We can't have positive overflow, but might have negative overflow. 46 if (x < half_min) 47 return true; 48 if (x >= 0) 49 return false; 50 // y >= INT_MIN && x >= half_min, 51 // so: y + x >= INT_MIN + half_min 52 // so: y - half_min + x >= INT_MAX 53 // so: (y - half_min + x) doesn't overflow. 54 // (y + x) < INT_MIN iff (y - half_min + x) < (INT_MIN - half_min) 55 return (y - half_min + x) < (INT_MIN - half_min); 56 } 57 // Neither negative nor positive overflow. 58 return false; 59 } 60 61 public: 62 INJECT(CheckedAdder()) = default; 63 64 virtual int add(int x, int y) override { 65 if (add_overflows(x, y)) { 66 std::cerr << "CheckedAdder: detected overflow during addition of " << x << " and " << y << std::endl; 67 abort(); 68 } 69 return x + y; 70 } 71 }; 72 73 fruit::Component<Adder> getCheckedAdderComponent() { 74 return fruit::createComponent().bind<Adder, CheckedAdder>(); 75 } 76