Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 0307f2a9ca7c7815bbd202cd68a2da8e749bfd1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*******************************************************************************
 * Copyright (c) 2007, 2008 Borland Software Corporation and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Borland Software Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.common.util;

import java.util.ArrayList;

/**
 * Implemens quick search of a line number for a given position within a string
 */
public class StringLineNumberProvider implements LineNumberProvider {
    
    /**
     * Creates a new StringLineNumberProvider object for the given string
     * @param s - the string to parse into lines
     */
    public StringLineNumberProvider(String s) {
        myLineEnds = new ArrayList<Integer>();
        parseString(s);
    }
    
    public int getLineEnd(int lineNumber) {
        return getLineEndInt(lineNumber - 1); 
    }
    
    public int getLineCount() {
        return myLineEnds.size();
    }
    
    public int getLineNumber(int offset){
        if (offset < 0) {
            return -1;
        }
        return getLineNumberInt(offset) + 1;
    }
    
    /* Internal implementation: zero-based line numeration */
    private int getLineEndInt(int lineNumber) {
        return ((Integer) myLineEnds.get(lineNumber)).intValue(); 
    }
    
    /* Internal implementation: zero-based line numeration
     * Dihotomic search of a line containig given offset 
     */
    public int getLineNumberInt(int offset){
        int a = 0;
        if (getLineEndInt(a) >= offset) {
            return a;
        }
        int b = myLineEnds.size() - 1;
        if (getLineEndInt(b) < offset) {
            return b;
        }
        int result = b;
        while (a <= b) {
            int c = (a + b) / 2;
            int cValue = getLineEndInt(c);
            if (cValue > offset) {
                result = c;
                b = c - 1;
            }
            else if (cValue < offset) {
                a = c + 1;
            }
            else return c;
        }
        return result;
    }

    /* Find out line ends */
    private void parseString(String s) {
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '\n') {
                myLineEnds.add(new Integer(i));
            }
            // Workaround for the case when \r is present and \n is lost
            if ((s.charAt(i) == '\r') && (i < s.length() - 1)) {
                if (s.charAt(i + 1) != '\n') {
                    myLineEnds.add(new Integer(i));
                }
            }
        }
        if ((s.length() != 0 ) && (
                myLineEnds.isEmpty() ||
                (getLineEndInt(getLineCount() - 1) != s.length() - 1)
           )) {
            myLineEnds.add(new Integer(s.length() - 1));
        }
    }

    private final ArrayList<Integer> myLineEnds;
}

Back to the top