1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "fidl/source_file.h"
6
7#include <assert.h>
8
9#include <algorithm>
10#include <functional>
11
12namespace fidl {
13
14SourceFile::SourceFile(std::string filename, std::string data)
15    : filename_(std::move(filename)), data_(std::move(data)) {
16    size_t size = 0u;
17    auto start_of_line = data_.cbegin();
18
19    for (auto it = data_.cbegin(); it != data_.cend(); ++it) {
20        ++size;
21        if (*it == '\n' || *it == '\0') {
22            auto& position = *start_of_line;
23            lines_.push_back(StringView(&position, size));
24
25            size = 0u;
26            start_of_line = it + 1;
27        }
28    }
29}
30
31SourceFile::~SourceFile() = default;
32
33StringView SourceFile::LineContaining(StringView view, Position* position_out) const {
34    auto ptr_less_equal = std::less_equal<const char*>();
35
36    assert(ptr_less_equal(data().data(), view.data()) && "The view is not part of this SourceFile");
37    assert(ptr_less_equal(view.data() + view.size(), data().data() + data().size()) &&
38           "The view is not part of this SourceFile");
39
40    // We are looking from the end of the file backwards (hence
41    // crbegin and crend), looking for the the first line (hence
42    // upper_bound) to start at or before before the token in
43    // question.
44    auto is_in_line = [&ptr_less_equal](const StringView& left, const StringView& right) {
45        return ptr_less_equal(right.data(), left.data());
46    };
47    auto line = std::upper_bound(lines_.crbegin(), lines_.crend(), view, is_in_line);
48    assert(line != lines_.crend());
49
50    if (position_out != nullptr) {
51        // Humans number lines from 1. Calculating this from the end
52        // accounts for this.
53        int line_number = lines_.crend() - line;
54        // But columns from 0!
55        int column_number = view.data() - line->data();
56        *position_out = {line_number, column_number};
57    }
58    return *line;
59}
60
61} // namespace fidl
62