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
30namespace WTF {
31
32
33/*
34 * Text Position
35 *
36 * TextPosition structure specifies coordinates within an text resource. It is used mostly
37 * for saving script source position. The third field 'generation' reflects the fact
38 * that in HTML document its any part can be generated on the fly, by a 'document.write'
39 * call. While elements of the generated part may still have coordinates (probably),
40 * we need to distinguish them from coordinates in the original text.
41 * So generation == 0 means that coordinates apply to original text,
42 * generation == 1 applies to a elements generated by a script in original text,
43 * generation == 2 to elements generated from a script in a generated part and so on.
44 *
45 * Later TextPosition0 and TextPosition1 and both number types can be merged together quite easily.
46 *
47 *
48 * 0-based and 1-based
49 *
50 * Line and column numbers could be interpreted as zero-based or 1-based. Since
51 * both practices coexist in WebKit source base, 'int' type should be replaced with
52 * a dedicated wrapper types, so that compiler helped us with this ambiguity.
53 *
54 * Here we introduce 2 types of numbers: ZeroBasedNumber and OneBasedNumber and
55 * 2 corresponding types of TextPosition structure. While only one type ought to be enough,
56 * this is done to keep transition to the new types as transparent as possible:
57 * e.g. in areas where 0-based integers are used, TextPosition0 should be introduced. This
58 * way all changes will remain trackable.
59 *
60 * Later both number types can be merged in one type quite easily.
61 *
62 * For type safety and for the future type merge it is important that all operations in API
63 * that accept or return integer have a name explicitly defining base of integer. For this reason
64 * int-receiving constructors are hidden from API.
65 */
66
67template<typename NUMBER>
68class TextPosition {
69public:
70 TextPosition(NUMBER line, NUMBER column, int generation)
71 : m_line(line)
72 , m_column(column)
73 , m_generation(generation)
74 {
75 }
76 TextPosition() {}
77
78 // A 'minimum' value of position, used as a default value.
79 static TextPosition<NUMBER> minimumPosition() { return TextPosition<NUMBER>(NUMBER::s_base, NUMBER::s_base, 0); }
80
81 // A value with line value less than a minimum; used as an impossible position.
82 static TextPosition<NUMBER> belowRangePosition() { return TextPosition<NUMBER>(NUMBER::s_belowBase, NUMBER::s_base, 0); }
83
84 NUMBER m_line;
85 NUMBER m_column;
86 int m_generation;
87};
88
89
90class OneBasedNumber;
91
92// An int wrapper that always reminds you that the number should be 0-based
93class ZeroBasedNumber {
94public:
95 static ZeroBasedNumber fromZeroBasedInt(int zeroBasedInt) { return ZeroBasedNumber(zeroBasedInt); }
96
97 ZeroBasedNumber() {}
98
99 int zeroBasedInt() const { return m_value; }
100
101 OneBasedNumber convertToOneBased() const;
102
103 static const ZeroBasedNumber s_base; // 0
104 static const ZeroBasedNumber s_belowBase; // -1
105
106private:
107 ZeroBasedNumber(int value) : m_value(value) {}
108 int m_value;
109};
110
111// An int wrapper that always reminds you that the number should be 1-based
112class OneBasedNumber {
113public:
114 static OneBasedNumber fromOneBasedInt(int oneBasedInt) { return OneBasedNumber(oneBasedInt); }
115 OneBasedNumber() {}
116
117 int oneBasedInt() const { return m_value; }
118 int convertAsZeroBasedInt() const { return m_value - 1; }
119 ZeroBasedNumber convertToZeroBased() const { return ZeroBasedNumber::fromZeroBasedInt(m_value - 1); }
120
121 static const OneBasedNumber s_base; // 1
122 static const OneBasedNumber s_belowBase; // 0
123
124private:
125 OneBasedNumber(int value) : m_value(value) {}
126 int m_value;
127};
128
129typedef TextPosition<ZeroBasedNumber> TextPosition0;
130typedef TextPosition<OneBasedNumber> TextPosition1;
131
132inline TextPosition0 toZeroBasedTextPosition(const TextPosition1& position)
133{
134 return TextPosition0(position.m_line.convertToZeroBased(), position.m_column.convertToZeroBased(), position.m_generation);
135}
136
137inline TextPosition1 toOneBasedTextPosition(const TextPosition0& position)
138{
139 return TextPosition1(position.m_line.convertToOneBased(), position.m_column.convertToOneBased(), position.m_generation);
140}
141
142inline OneBasedNumber ZeroBasedNumber::convertToOneBased() const
143{
144 return OneBasedNumber::fromOneBasedInt(m_value + 1);
145}
146
147}
148
149
150using WTF::TextPosition0;
151using WTF::TextPosition1;
152
153#endif // TextPosition_h