Home | History | Annotate | Download | only in text
      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