]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
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 |