1 /* 2 * Copyright (C) 2010, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #ifndef TextPosition_h 26 #define TextPosition_h 27 28 #include <wtf/Assertions.h> 29 30 namespace WTF { 31 32 /* 33 * Text Position 34 * 35 * TextPosition structure specifies coordinates within an text resource. It is used mostly 36 * for saving script source position. 37 * 38 * Later TextPosition0 and TextPosition1 and both number types can be merged together quite easily. 39 * 40 * 0-based and 1-based 41 * 42 * Line and column numbers could be interpreted as zero-based or 1-based. Since 43 * both practices coexist in WebKit source base, 'int' type should be replaced with 44 * a dedicated wrapper types, so that compiler helped us with this ambiguity. 45 * 46 * Here we introduce 2 types of numbers: ZeroBasedNumber and OneBasedNumber and 47 * 2 corresponding types of TextPosition structure. While only one type ought to be enough, 48 * this is done to keep transition to the new types as transparent as possible: 49 * e.g. in areas where 0-based integers are used, TextPosition0 should be introduced. This 50 * way all changes will remain trackable. 51 * 52 * Later both number types can be merged in one type quite easily. 53 * 54 * For type safety and for the future type merge it is important that all operations in API 55 * that accept or return integer have a name explicitly defining base of integer. For this reason 56 * int-receiving constructors are hidden from API. 57 */ 58 59 template<typename NUMBER> 60 class TextPosition { 61 public: 62 TextPosition(NUMBER line, NUMBER column) 63 : m_line(line) 64 , m_column(column) 65 { 66 } 67 TextPosition() {} 68 69 bool operator==(const TextPosition& other) { return m_line == other.m_line && m_column == other.m_column; } 70 bool operator!=(const TextPosition& other) { return !((*this) == other); } 71 72 // A 'minimum' value of position, used as a default value. 73 static TextPosition<NUMBER> minimumPosition() { return TextPosition<NUMBER>(NUMBER::base(), NUMBER::base()); } 74 75 // A value with line value less than a minimum; used as an impossible position. 76 static TextPosition<NUMBER> belowRangePosition() { return TextPosition<NUMBER>(NUMBER::belowBase(), NUMBER::belowBase()); } 77 78 NUMBER m_line; 79 NUMBER m_column; 80 }; 81 82 class OneBasedNumber; 83 84 // An int wrapper that always reminds you that the number should be 0-based 85 class ZeroBasedNumber { 86 public: 87 static ZeroBasedNumber fromZeroBasedInt(int zeroBasedInt) { return ZeroBasedNumber(zeroBasedInt); } 88 89 ZeroBasedNumber() {} 90 91 int zeroBasedInt() const { return m_value; } 92 int convertAsOneBasedInt() const { return m_value + 1; } 93 OneBasedNumber convertToOneBased() const; 94 95 bool operator==(ZeroBasedNumber other) { return m_value == other.m_value; } 96 bool operator!=(ZeroBasedNumber other) { return !((*this) == other); } 97 98 static ZeroBasedNumber base() { return 0; } 99 static ZeroBasedNumber belowBase() { return -1; } 100 101 private: 102 ZeroBasedNumber(int value) : m_value(value) {} 103 int m_value; 104 }; 105 106 // An int wrapper that always reminds you that the number should be 1-based 107 class OneBasedNumber { 108 public: 109 static OneBasedNumber fromOneBasedInt(int oneBasedInt) { return OneBasedNumber(oneBasedInt); } 110 OneBasedNumber() {} 111 112 int oneBasedInt() const { return m_value; } 113 int convertAsZeroBasedInt() const { return m_value - 1; } 114 ZeroBasedNumber convertToZeroBased() const { return ZeroBasedNumber::fromZeroBasedInt(m_value - 1); } 115 116 bool operator==(OneBasedNumber other) { return m_value == other.m_value; } 117 bool operator!=(OneBasedNumber other) { return !((*this) == other); } 118 119 static OneBasedNumber base() { return 1; } 120 static OneBasedNumber belowBase() { return 0; } 121 122 private: 123 OneBasedNumber(int value) : m_value(value) {} 124 int m_value; 125 }; 126 127 typedef TextPosition<ZeroBasedNumber> TextPosition0; 128 typedef TextPosition<OneBasedNumber> TextPosition1; 129 130 inline TextPosition0 toZeroBasedTextPosition(const TextPosition1& position) 131 { 132 return TextPosition0(position.m_line.convertToZeroBased(), position.m_column.convertToZeroBased()); 133 } 134 135 inline TextPosition1 toOneBasedTextPosition(const TextPosition0& position) 136 { 137 return TextPosition1(position.m_line.convertToOneBased(), position.m_column.convertToOneBased()); 138 } 139 140 inline OneBasedNumber ZeroBasedNumber::convertToOneBased() const 141 { 142 return OneBasedNumber::fromOneBasedInt(m_value + 1); 143 } 144 145 } 146 147 using WTF::TextPosition0; 148 using WTF::TextPosition1; 149 150 #endif // TextPosition_h 151