<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) Andrey Mnatsakanov
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "opengl_render_state.hpp"
#include <pangolin/display/opengl_render_state.h>
#include <pybind11/operators.h>
#include <pybind11/numpy.h>

namespace py_pangolin {

  void bind_opengl_render_state(pybind11::module &m){
    pybind11::enum_<pangolin::AxisDirection>(m, "AxisDirection")
      .value("AxisNone", pangolin::AxisDirection::AxisNone)
      .value("AxisNegX", pangolin::AxisDirection::AxisNegX)
      .value("AxisNegY", pangolin::AxisDirection::AxisNegY)
      .value("AxisNegZ", pangolin::AxisDirection::AxisNegZ)
      .value("AxisX", pangolin::AxisDirection::AxisX)
      .value("AxisY", pangolin::AxisDirection::AxisY)
      .value("AxisZ", pangolin::AxisDirection::AxisZ)
      .export_values();

    pybind11::enum_<pangolin::OpenGlStack>(m, "OpenGlStack")
      .value("GlModelViewStack", pangolin::OpenGlStack::GlModelViewStack)
      .value("GlProjectionStack", pangolin::OpenGlStack::GlProjectionStack)
      .value("GlTextureStack", pangolin::OpenGlStack::GlTextureStack)
      .export_values();

    pybind11::class_<pangolin::OpenGlMatrix>(m, "OpenGlMatrix")
      .def("Translate", &pangolin::OpenGlMatrix::Translate)
      .def("Scale", &pangolin::OpenGlMatrix::Scale)
      .def("RotateX", &pangolin::OpenGlMatrix::RotateX)
      .def("RotateY", &pangolin::OpenGlMatrix::RotateY)
      .def("RotateZ", &pangolin::OpenGlMatrix::RotateX)
      .def(pybind11::init<>())
      .def("Load", &pangolin::OpenGlMatrix::Load)
      .def("Multiply", &pangolin::OpenGlMatrix::Multiply)
      .def("SetIdentity", &pangolin::OpenGlMatrix::SetIdentity)
      .def("Transpose", &pangolin::OpenGlMatrix::Transpose)
      .def("Inverse", &pangolin::OpenGlMatrix::Inverse)
      .def("Matrix", [](pangolin::OpenGlMatrix& mat){
            using T = pangolin::GLprecision;
            return pybind11::array_t<T>( {4, 4 }, {1*sizeof(T), 4*sizeof(T)}, mat.m );
      })
      .def(pybind11::self * pybind11::self);

    pybind11::class_<pangolin::OpenGlMatrixSpec, pangolin::OpenGlMatrix>(m, "OpenGlMatrixSpec")
      .def(pybind11::init<>());

    m.def("ProjectionMatrixRUB_BottomLeft", &pangolin::ProjectionMatrixRUB_BottomLeft);
    m.def("ProjectionMatrixRUB_TopLeft", &pangolin::ProjectionMatrixRUB_TopLeft);
    m.def("ProjectionMatrixRDF_BottomLeft", &pangolin::ProjectionMatrixRDF_BottomLeft);
    m.def("ProjectionMatrixRDF_TopLeft", &pangolin::ProjectionMatrixRDF_TopLeft);
    m.def("ProjectionMatrix", &pangolin::ProjectionMatrix);
    m.def("ProjectionMatrixOrthographic", &pangolin::ProjectionMatrixOrthographic);
    m.def("ModelViewLookAtRUB", &pangolin::ModelViewLookAtRUB);
    m.def("ModelViewLookAtRDF", &pangolin::ModelViewLookAtRDF);
    m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::AxisDirection))&pangolin::ModelViewLookAt);
    m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision))&pangolin::ModelViewLookAt);
    m.def("IdentityMatrix", (pangolin::OpenGlMatrix (*)())&pangolin::IdentityMatrix);
    m.def("IdentityMatrix", (pangolin::OpenGlMatrixSpec (*)(pangolin::OpenGlStack))&pangolin::IdentityMatrix);
    m.def("negIdentityMatrix", &pangolin::negIdentityMatrix);

    pybind11::class_<pangolin::OpenGlRenderState>(m, "OpenGlRenderState")
      .def(pybind11::init<const pangolin::OpenGlMatrix&>())
      .def(pybind11::init<const pangolin::OpenGlMatrix&, const pangolin::OpenGlMatrix&>())
      .def(pybind11::init<>())
      .def("ApplyIdentity", &pangolin::OpenGlRenderState::ApplyIdentity)
      .def("Apply", &pangolin::OpenGlRenderState::Apply)
      .def("SetProjectionMatrix", &pangolin::OpenGlRenderState::SetProjectionMatrix)
      .def("SetModelViewMatrix", &pangolin::OpenGlRenderState::SetModelViewMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("GetProjectionModelViewMatrix", &pangolin::OpenGlRenderState::GetProjectionModelViewMatrix)
      .def("GetProjectiveTextureMatrix", &pangolin::OpenGlRenderState::GetProjectiveTextureMatrix)
      .def("EnableProjectiveTexturing", &pangolin::OpenGlRenderState::EnableProjectiveTexturing)
      .def("DisableProjectiveTexturing", &pangolin::OpenGlRenderState::DisableProjectiveTexturing)
      .def("Follow", &pangolin::OpenGlRenderState::Follow, pybind11::arg("T_wc"), pybind11::arg("follow")=true)
      .def("Unfollow", &pangolin::OpenGlRenderState::Unfollow)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetViewOffset", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetViewOffset)
      .def("GetViewOffset", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetViewOffset)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(int) const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("ApplyNView", &pangolin::OpenGlRenderState::ApplyNView);
  }

}  // py_pangolin
<commit_msg>Fixing typo in pybind module<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) Andrey Mnatsakanov
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include "opengl_render_state.hpp"
#include <pangolin/display/opengl_render_state.h>
#include <pybind11/operators.h>
#include <pybind11/numpy.h>

namespace py_pangolin {

  void bind_opengl_render_state(pybind11::module &m){
    pybind11::enum_<pangolin::AxisDirection>(m, "AxisDirection")
      .value("AxisNone", pangolin::AxisDirection::AxisNone)
      .value("AxisNegX", pangolin::AxisDirection::AxisNegX)
      .value("AxisNegY", pangolin::AxisDirection::AxisNegY)
      .value("AxisNegZ", pangolin::AxisDirection::AxisNegZ)
      .value("AxisX", pangolin::AxisDirection::AxisX)
      .value("AxisY", pangolin::AxisDirection::AxisY)
      .value("AxisZ", pangolin::AxisDirection::AxisZ)
      .export_values();

    pybind11::enum_<pangolin::OpenGlStack>(m, "OpenGlStack")
      .value("GlModelViewStack", pangolin::OpenGlStack::GlModelViewStack)
      .value("GlProjectionStack", pangolin::OpenGlStack::GlProjectionStack)
      .value("GlTextureStack", pangolin::OpenGlStack::GlTextureStack)
      .export_values();

    pybind11::class_<pangolin::OpenGlMatrix>(m, "OpenGlMatrix")
      .def("Translate", &pangolin::OpenGlMatrix::Translate)
      .def("Scale", &pangolin::OpenGlMatrix::Scale)
      .def("RotateX", &pangolin::OpenGlMatrix::RotateX)
      .def("RotateY", &pangolin::OpenGlMatrix::RotateY)
      .def("RotateZ", &pangolin::OpenGlMatrix::RotateZ)
      .def(pybind11::init<>())
      .def("Load", &pangolin::OpenGlMatrix::Load)
      .def("Multiply", &pangolin::OpenGlMatrix::Multiply)
      .def("SetIdentity", &pangolin::OpenGlMatrix::SetIdentity)
      .def("Transpose", &pangolin::OpenGlMatrix::Transpose)
      .def("Inverse", &pangolin::OpenGlMatrix::Inverse)
      .def("Matrix", [](pangolin::OpenGlMatrix& mat){
            using T = pangolin::GLprecision;
            return pybind11::array_t<T>( {4, 4 }, {1*sizeof(T), 4*sizeof(T)}, mat.m );
      })
      .def(pybind11::self * pybind11::self);

    pybind11::class_<pangolin::OpenGlMatrixSpec, pangolin::OpenGlMatrix>(m, "OpenGlMatrixSpec")
      .def(pybind11::init<>());

    m.def("ProjectionMatrixRUB_BottomLeft", &pangolin::ProjectionMatrixRUB_BottomLeft);
    m.def("ProjectionMatrixRUB_TopLeft", &pangolin::ProjectionMatrixRUB_TopLeft);
    m.def("ProjectionMatrixRDF_BottomLeft", &pangolin::ProjectionMatrixRDF_BottomLeft);
    m.def("ProjectionMatrixRDF_TopLeft", &pangolin::ProjectionMatrixRDF_TopLeft);
    m.def("ProjectionMatrix", &pangolin::ProjectionMatrix);
    m.def("ProjectionMatrixOrthographic", &pangolin::ProjectionMatrixOrthographic);
    m.def("ModelViewLookAtRUB", &pangolin::ModelViewLookAtRUB);
    m.def("ModelViewLookAtRDF", &pangolin::ModelViewLookAtRDF);
    m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::AxisDirection))&pangolin::ModelViewLookAt);
    m.def("ModelViewLookAt", (pangolin::OpenGlMatrix (*)(pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision, pangolin::GLprecision))&pangolin::ModelViewLookAt);
    m.def("IdentityMatrix", (pangolin::OpenGlMatrix (*)())&pangolin::IdentityMatrix);
    m.def("IdentityMatrix", (pangolin::OpenGlMatrixSpec (*)(pangolin::OpenGlStack))&pangolin::IdentityMatrix);
    m.def("negIdentityMatrix", &pangolin::negIdentityMatrix);

    pybind11::class_<pangolin::OpenGlRenderState>(m, "OpenGlRenderState")
      .def(pybind11::init<const pangolin::OpenGlMatrix&>())
      .def(pybind11::init<const pangolin::OpenGlMatrix&, const pangolin::OpenGlMatrix&>())
      .def(pybind11::init<>())
      .def("ApplyIdentity", &pangolin::OpenGlRenderState::ApplyIdentity)
      .def("Apply", &pangolin::OpenGlRenderState::Apply)
      .def("SetProjectionMatrix", &pangolin::OpenGlRenderState::SetProjectionMatrix)
      .def("SetModelViewMatrix", &pangolin::OpenGlRenderState::SetModelViewMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)())&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)() const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("GetProjectionModelViewMatrix", &pangolin::OpenGlRenderState::GetProjectionModelViewMatrix)
      .def("GetProjectiveTextureMatrix", &pangolin::OpenGlRenderState::GetProjectiveTextureMatrix)
      .def("EnableProjectiveTexturing", &pangolin::OpenGlRenderState::EnableProjectiveTexturing)
      .def("DisableProjectiveTexturing", &pangolin::OpenGlRenderState::DisableProjectiveTexturing)
      .def("Follow", &pangolin::OpenGlRenderState::Follow, pybind11::arg("T_wc"), pybind11::arg("follow")=true)
      .def("Unfollow", &pangolin::OpenGlRenderState::Unfollow)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetProjectionMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetProjectionMatrix)
      .def("GetViewOffset", (pangolin::OpenGlMatrix& (pangolin::OpenGlRenderState::*)(unsigned int))&pangolin::OpenGlRenderState::GetViewOffset)
      .def("GetViewOffset", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(unsigned int) const)&pangolin::OpenGlRenderState::GetViewOffset)
      .def("GetModelViewMatrix", (pangolin::OpenGlMatrix (pangolin::OpenGlRenderState::*)(int) const)&pangolin::OpenGlRenderState::GetModelViewMatrix)
      .def("ApplyNView", &pangolin::OpenGlRenderState::ApplyNView);
  }

}  // py_pangolin
<|endoftext|>


<commit_before>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hook_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const String& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0),
      m_option_manager(GlobalOptionManager::instance())
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHookManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHookManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    BufferManager::instance().unregister_buffer(this);
    assert(m_iterators_to_update.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    return BufferIterator(*this, clamp(line_and_column));
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    return iterator.m_coord;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    return iterator.line();
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(line < line_count());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1].start : length();
    return end - m_lines[line].start;
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line) - 2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, { iterator.line(), 0 });
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = iterator.line();
    return ++BufferIterator(*this, { line, std::max(line_length(line) - 1, 0) });
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, { 0, 0 });
}

BufferIterator Buffer::end() const
{
    if (m_lines.empty())
        return BufferIterator(*this, { 0, 0 });
    return BufferIterator(*this, { (int)line_count()-1, (int)m_lines.back().length() });
}

BufferSize Buffer::length() const
{
    if (m_lines.empty())
        return 0;
    return m_lines.back().start + m_lines.back().length();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    String res;
    for (BufferPos line = begin.line(); line <= end.line(); ++line)
    {
       size_t start = 0;
       if (line == begin.line())
           start = begin.column();
       size_t count = -1;
       if (line == end.line())
           count = end.column() - start;
       res += m_lines[line].content.substr(start, count);
    }
    return res;
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::check_invariant() const
{
    BufferSize start = 0;
    for (auto& line : m_lines)
    {
        assert(line.start == start);
        assert(line.length() > 0);
        start += line.length();
    }
}

void Buffer::insert(const BufferIterator& pos, const String& content)
{
    BufferSize offset = pos.offset();

    // all following lines advanced by length
    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start += content.length();

    BufferCoord end_pos;
    // if we inserted at the end of the buffer, we may have created a new
    // line without inserting a '\n'
    if (pos == end() and (pos == begin() or *(pos-1) == '\n'))
    {
        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                m_lines.push_back({ offset + start, content.substr(start, i + 1 - start) });
                start = i + 1;
            }
        }
        if (start != content.length())
            m_lines.push_back({ offset + start, content.substr(start) });

        end_pos = end().m_coord;
    }
    else
    {
        String prefix = m_lines[pos.line()].content.substr(0, pos.column());
        String suffix = m_lines[pos.line()].content.substr(pos.column());

        auto line_it = m_lines.begin() + pos.line();
        line_it = m_lines.erase(line_it);

        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                String line_content = content.substr(start, i + 1 - start);
                if (start == 0)
                {
                    line_content = prefix + line_content;
                    line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(),
                                                        std::move(line_content) });
                }
                else
                    line_it = m_lines.insert(line_it, { offset + start,
                                                        std::move(line_content) });

                ++line_it;
                start = i + 1;
            }
        }
        if (start == 0)
            line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(), prefix + content + suffix });
        else
            line_it = m_lines.insert(line_it, { offset + start, content.substr(start) + suffix });

        end_pos = { int(line_it - m_lines.begin()), int(line_it->length() - suffix.length()) };
    }

    check_invariant();

    for (auto iterator : m_iterators_to_update)
        iterator->on_insert(pos.m_coord, end_pos);
}

void Buffer::erase(const BufferIterator& pos, BufferSize length)
{
    BufferIterator end = pos + length;
    String prefix = m_lines[pos.line()].content.substr(0, pos.column());
    String suffix = m_lines[end.line()].content.substr(end.column());
    Line new_line = { m_lines[pos.line()].start, prefix + suffix };

    m_lines.erase(m_lines.begin() + pos.line(), m_lines.begin() + end.line() + 1);
    if (new_line.length())
        m_lines.insert(m_lines.begin() + pos.line(), std::move(new_line));

    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start -= length;

    check_invariant();

    for (auto iterator : m_iterators_to_update)
        iterator->on_erase(pos.m_coord, end.m_coord);
}

void Buffer::apply_modification(const Modification& modification)
{
    const String& content = modification.content;
    const BufferIterator& pos = modification.position;

    switch (modification.type)
    {
    case Modification::Insert:
    {
        BufferIterator pos = modification.position < end() ?
                             modification.position : end();
        insert(pos, modification.content);
        break;
    }
    case Modification::Erase:
    {
        size_t count = modification.content.length();
        assert(string(modification.position, modification.position + count)
               == modification.content);
        erase(modification.position, count);
        break;
    }
    default:
        assert(false);
    }
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::add_iterator_to_update(BufferIterator& iterator)
{
    assert(not contains(m_iterators_to_update, &iterator));
    m_iterators_to_update.push_back(&iterator);
}

void Buffer::remove_iterator_from_update(BufferIterator& iterator)
{
    auto it = std::find(m_iterators_to_update.begin(),
                        m_iterators_to_update.end(),
                        &iterator);
    assert(it != m_iterators_to_update.end());
    m_iterators_to_update.erase(it);
}

}
<commit_msg>check if no modification were made in Buffer::end_undo_group<commit_after>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hook_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const String& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0),
      m_option_manager(GlobalOptionManager::instance())
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHookManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHookManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    BufferManager::instance().unregister_buffer(this);
    assert(m_iterators_to_update.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    return BufferIterator(*this, clamp(line_and_column));
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    return iterator.m_coord;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    return iterator.line();
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(line < line_count());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1].start : length();
    return end - m_lines[line].start;
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line) - 2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, { iterator.line(), 0 });
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = iterator.line();
    return ++BufferIterator(*this, { line, std::max(line_length(line) - 1, 0) });
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, { 0, 0 });
}

BufferIterator Buffer::end() const
{
    if (m_lines.empty())
        return BufferIterator(*this, { 0, 0 });
    return BufferIterator(*this, { (int)line_count()-1, (int)m_lines.back().length() });
}

BufferSize Buffer::length() const
{
    if (m_lines.empty())
        return 0;
    return m_lines.back().start + m_lines.back().length();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    String res;
    for (BufferPos line = begin.line(); line <= end.line(); ++line)
    {
       size_t start = 0;
       if (line == begin.line())
           start = begin.column();
       size_t count = -1;
       if (line == end.line())
           count = end.column() - start;
       res += m_lines[line].content.substr(start, count);
    }
    return res;
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    if (m_current_undo_group.empty())
        return;

    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::check_invariant() const
{
    BufferSize start = 0;
    for (auto& line : m_lines)
    {
        assert(line.start == start);
        assert(line.length() > 0);
        start += line.length();
    }
}

void Buffer::insert(const BufferIterator& pos, const String& content)
{
    BufferSize offset = pos.offset();

    // all following lines advanced by length
    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start += content.length();

    BufferCoord end_pos;
    // if we inserted at the end of the buffer, we may have created a new
    // line without inserting a '\n'
    if (pos == end() and (pos == begin() or *(pos-1) == '\n'))
    {
        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                m_lines.push_back({ offset + start, content.substr(start, i + 1 - start) });
                start = i + 1;
            }
        }
        if (start != content.length())
            m_lines.push_back({ offset + start, content.substr(start) });

        end_pos = end().m_coord;
    }
    else
    {
        String prefix = m_lines[pos.line()].content.substr(0, pos.column());
        String suffix = m_lines[pos.line()].content.substr(pos.column());

        auto line_it = m_lines.begin() + pos.line();
        line_it = m_lines.erase(line_it);

        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                String line_content = content.substr(start, i + 1 - start);
                if (start == 0)
                {
                    line_content = prefix + line_content;
                    line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(),
                                                        std::move(line_content) });
                }
                else
                    line_it = m_lines.insert(line_it, { offset + start,
                                                        std::move(line_content) });

                ++line_it;
                start = i + 1;
            }
        }
        if (start == 0)
            line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(), prefix + content + suffix });
        else
            line_it = m_lines.insert(line_it, { offset + start, content.substr(start) + suffix });

        end_pos = { int(line_it - m_lines.begin()), int(line_it->length() - suffix.length()) };
    }

    check_invariant();

    for (auto iterator : m_iterators_to_update)
        iterator->on_insert(pos.m_coord, end_pos);
}

void Buffer::erase(const BufferIterator& pos, BufferSize length)
{
    BufferIterator end = pos + length;
    String prefix = m_lines[pos.line()].content.substr(0, pos.column());
    String suffix = m_lines[end.line()].content.substr(end.column());
    Line new_line = { m_lines[pos.line()].start, prefix + suffix };

    m_lines.erase(m_lines.begin() + pos.line(), m_lines.begin() + end.line() + 1);
    if (new_line.length())
        m_lines.insert(m_lines.begin() + pos.line(), std::move(new_line));

    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start -= length;

    check_invariant();

    for (auto iterator : m_iterators_to_update)
        iterator->on_erase(pos.m_coord, end.m_coord);
}

void Buffer::apply_modification(const Modification& modification)
{
    const String& content = modification.content;
    const BufferIterator& pos = modification.position;

    switch (modification.type)
    {
    case Modification::Insert:
    {
        BufferIterator pos = modification.position < end() ?
                             modification.position : end();
        insert(pos, modification.content);
        break;
    }
    case Modification::Erase:
    {
        size_t count = modification.content.length();
        assert(string(modification.position, modification.position + count)
               == modification.content);
        erase(modification.position, count);
        break;
    }
    default:
        assert(false);
    }
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::add_iterator_to_update(BufferIterator& iterator)
{
    assert(not contains(m_iterators_to_update, &iterator));
    m_iterators_to_update.push_back(&iterator);
}

void Buffer::remove_iterator_from_update(BufferIterator& iterator)
{
    auto it = std::find(m_iterators_to_update.begin(),
                        m_iterators_to_update.end(),
                        &iterator);
    assert(it != m_iterators_to_update.end());
    m_iterators_to_update.erase(it);
}

}
<|endoftext|>


<commit_before>#include <boost/algorithm/string.hpp>
#include <iostream>
using namespace std;

const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

string encrypt(const string& plaintext, const string& keyword)
{
  /* Returns the ciphertext produced by encrypting the plaintext using the
   * given keyword and the Vigenere Cipher
   * (http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher).
   */

  string ciphertext = "";

  string caps_keyword = boost::algorithm::to_upper_copy<string>(keyword);
  string caps_plaintext = boost::algorithm::to_upper_copy<string>(plaintext);

  string keyphrase = "";
  for (int i = 0; i < plaintext.length() / keyword.length() + 1; i++)
  {
    keyphrase += caps_keyword;
  }
  keyphrase.resize(plaintext.length());

  for (int i = 0; i < plaintext.length(); i++)
  {
    int start_index = alphabet.find(caps_plaintext[i]);
    int advance_by = alphabet.find(keyphrase[i]);
    int new_index = (start_index + advance_by) % alphabet.length();

    ciphertext += alphabet[new_index];
  }

  return ciphertext;
}

string decrypt(const string& ciphertext, const string& keyword)
{
  /* Returns the plaintext produced by decrypting the ciphertext using the
   * given keyword and the Vigenere Cipher
   * (http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher).
   */
  string plaintext = "";

  // XXXX: Finish me!

  return plaintext;
}
<commit_msg>get_keyphrase method.<commit_after>#include <boost/algorithm/string.hpp>
#include <iostream>
using namespace std;

const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

string get_keyphrase(const string& keyword, const string& text)
{
  /* Returns the Vigenere keyword of appropriate length (in all caps) for a
   * given keyword and text (either plaintext or ciphertext).
   */

  return "TODO";
}

string encrypt(const string& plaintext, const string& keyword)
{
  /* Returns the ciphertext produced by encrypting the plaintext using the
   * given keyword and the Vigenere Cipher
   * (http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher).
   */

  string ciphertext = "";

  string caps_keyword = boost::algorithm::to_upper_copy<string>(keyword);
  string caps_plaintext = boost::algorithm::to_upper_copy<string>(plaintext);

  string keyphrase = "";
  for (int i = 0; i < plaintext.length() / keyword.length() + 1; i++)
  {
    keyphrase += caps_keyword;
  }
  keyphrase.resize(plaintext.length());

  for (int i = 0; i < plaintext.length(); i++)
  {
    int start_index = alphabet.find(caps_plaintext[i]);
    int advance_by = alphabet.find(keyphrase[i]);
    int new_index = (start_index + advance_by) % alphabet.length();

    ciphertext += alphabet[new_index];
  }

  return ciphertext;
}

string decrypt(const string& ciphertext, const string& keyword)
{
  /* Returns the plaintext produced by decrypting the ciphertext using the
   * given keyword and the Vigenere Cipher
   * (http://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher).
   */
  string plaintext = "";

  // XXXX: Finish me!

  return plaintext;
}
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#ifndef EIGEN_NO_ASSERTION_CHECKING
#define EIGEN_NO_ASSERTION_CHECKING
#endif

static int nb_temporaries;

#define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; }

#include "main.h"
#include <Eigen/Cholesky>
#include <Eigen/QR>

#define VERIFY_EVALUATION_COUNT(XPR,N) {\
    nb_temporaries = 0; \
    XPR; \
    if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
    VERIFY( (#XPR) && nb_temporaries==N ); \
  }

#ifdef HAS_GSL
#include "gsl_helper.h"
#endif

template<typename MatrixType> void cholesky(const MatrixType& m)
{
  /* this test covers the following files:
     LLT.h LDLT.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  MatrixType a0 = MatrixType::Random(rows,cols);
  VectorType vecB = VectorType::Random(rows), vecX(rows);
  MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
  SquareMatrixType symm =  a0 * a0.adjoint();
  // let's make sure the matrix is not singular or near singular
  for (int k=0; k<3; ++k)
  {
    MatrixType a1 = MatrixType::Random(rows,cols);
    symm += a1 * a1.adjoint();
  }

  SquareMatrixType symmUp = symm.template triangularView<Upper>();
  SquareMatrixType symmLo = symm.template triangularView<Lower>();

  // to test if really Cholesky only uses the upper triangular part, uncomment the following
  // FIXME: currently that fails !!
  //symm.template part<StrictlyLower>().setZero();

  #ifdef HAS_GSL
//   if (ei_is_same_type<RealScalar,double>::ret)
//   {
//     typedef GslTraits<Scalar> Gsl;
//     typename Gsl::Matrix gMatA=0, gSymm=0;
//     typename Gsl::Vector gVecB=0, gVecX=0;
//     convert<MatrixType>(symm, gSymm);
//     convert<MatrixType>(symm, gMatA);
//     convert<VectorType>(vecB, gVecB);
//     convert<VectorType>(vecB, gVecX);
//     Gsl::cholesky(gMatA);
//     Gsl::cholesky_solve(gMatA, gVecB, gVecX);
//     VectorType vecX(rows), _vecX, _vecB;
//     convert(gVecX, _vecX);
//     symm.llt().solve(vecB, &vecX);
//     Gsl::prod(gSymm, gVecX, gVecB);
//     convert(gVecB, _vecB);
//     // test gsl itself !
//     VERIFY_IS_APPROX(vecB, _vecB);
//     VERIFY_IS_APPROX(vecX, _vecX);
//
//     Gsl::free(gMatA);
//     Gsl::free(gSymm);
//     Gsl::free(gVecB);
//     Gsl::free(gVecX);
//   }
  #endif

  {
    LLT<SquareMatrixType,Lower> chollo(symmLo);
    VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
    vecX = chollo.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = chollo.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

    // test the upper mode
    LLT<SquareMatrixType,Upper> cholup(symmUp);
    VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix());
    vecX = cholup.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = cholup.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);
  }

  int sign = ei_random<int>()%2 ? 1 : -1;

  if(sign == -1)
  {
    symm = -symm; // test a negative matrix
  }

  {
    LDLT<SquareMatrixType,Lower> ldltlo(symm);
    VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
    vecX = ldltlo.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = ldltlo.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

    LDLT<SquareMatrixType,Upper> ldltup(symm);
    VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
    vecX = ldltup.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = ldltup.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

    if(MatrixType::RowsAtCompileTime==Dynamic)
    {
      // note : each inplace permutation requires a small temporary vector (mask)

      // check inplace solve
      matX = matB;
      VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0);
      VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval());

      matX = matB;
      VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0);
      VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval());
    }
  }

}

template<typename MatrixType> void cholesky_verify_assert()
{
  MatrixType tmp;

  LLT<MatrixType> llt;
  VERIFY_RAISES_ASSERT(llt.matrixL())
  VERIFY_RAISES_ASSERT(llt.matrixU())
  VERIFY_RAISES_ASSERT(llt.solve(tmp))
  VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))

  LDLT<MatrixType> ldlt;
  VERIFY_RAISES_ASSERT(ldlt.matrixL())
  VERIFY_RAISES_ASSERT(ldlt.permutationP())
  VERIFY_RAISES_ASSERT(ldlt.vectorD())
  VERIFY_RAISES_ASSERT(ldlt.isPositive())
  VERIFY_RAISES_ASSERT(ldlt.isNegative())
  VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
  VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
}

void test_cholesky()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( cholesky(MatrixXd(1,1)) );
    CALL_SUBTEST_3( cholesky(Matrix2d()) );
    CALL_SUBTEST_4( cholesky(Matrix3f()) );
    CALL_SUBTEST_5( cholesky(Matrix4d()) );
    CALL_SUBTEST_2( cholesky(MatrixXd(200,200)) );
    CALL_SUBTEST_6( cholesky(MatrixXcd(100,100)) );
  }

  CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() );
  CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() );
  CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() );
  CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() );

  // Test problem size constructors
  CALL_SUBTEST_9( LLT<MatrixXf>(10) );
  CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
}
<commit_msg>fix ldlt unit test<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#ifndef EIGEN_NO_ASSERTION_CHECKING
#define EIGEN_NO_ASSERTION_CHECKING
#endif

static int nb_temporaries;

#define EIGEN_DEBUG_MATRIX_CTOR { if(size!=0) nb_temporaries++; }

#include "main.h"
#include <Eigen/Cholesky>
#include <Eigen/QR>

#define VERIFY_EVALUATION_COUNT(XPR,N) {\
    nb_temporaries = 0; \
    XPR; \
    if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
    VERIFY( (#XPR) && nb_temporaries==N ); \
  }

#ifdef HAS_GSL
#include "gsl_helper.h"
#endif

template<typename MatrixType> void cholesky(const MatrixType& m)
{
  /* this test covers the following files:
     LLT.h LDLT.h
  */
  int rows = m.rows();
  int cols = m.cols();

  typedef typename MatrixType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  MatrixType a0 = MatrixType::Random(rows,cols);
  VectorType vecB = VectorType::Random(rows), vecX(rows);
  MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols);
  SquareMatrixType symm =  a0 * a0.adjoint();
  // let's make sure the matrix is not singular or near singular
  for (int k=0; k<3; ++k)
  {
    MatrixType a1 = MatrixType::Random(rows,cols);
    symm += a1 * a1.adjoint();
  }

  SquareMatrixType symmUp = symm.template triangularView<Upper>();
  SquareMatrixType symmLo = symm.template triangularView<Lower>();

  // to test if really Cholesky only uses the upper triangular part, uncomment the following
  // FIXME: currently that fails !!
  //symm.template part<StrictlyLower>().setZero();

  #ifdef HAS_GSL
//   if (ei_is_same_type<RealScalar,double>::ret)
//   {
//     typedef GslTraits<Scalar> Gsl;
//     typename Gsl::Matrix gMatA=0, gSymm=0;
//     typename Gsl::Vector gVecB=0, gVecX=0;
//     convert<MatrixType>(symm, gSymm);
//     convert<MatrixType>(symm, gMatA);
//     convert<VectorType>(vecB, gVecB);
//     convert<VectorType>(vecB, gVecX);
//     Gsl::cholesky(gMatA);
//     Gsl::cholesky_solve(gMatA, gVecB, gVecX);
//     VectorType vecX(rows), _vecX, _vecB;
//     convert(gVecX, _vecX);
//     symm.llt().solve(vecB, &vecX);
//     Gsl::prod(gSymm, gVecX, gVecB);
//     convert(gVecB, _vecB);
//     // test gsl itself !
//     VERIFY_IS_APPROX(vecB, _vecB);
//     VERIFY_IS_APPROX(vecX, _vecX);
//
//     Gsl::free(gMatA);
//     Gsl::free(gSymm);
//     Gsl::free(gVecB);
//     Gsl::free(gVecX);
//   }
  #endif

  {
    LLT<SquareMatrixType,Lower> chollo(symmLo);
    VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix());
    vecX = chollo.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = chollo.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

    // test the upper mode
    LLT<SquareMatrixType,Upper> cholup(symmUp);
    VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix());
    vecX = cholup.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = cholup.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);
  }

  int sign = ei_random<int>()%2 ? 1 : -1;

  if(sign == -1)
  {
    symm = -symm; // test a negative matrix
  }

  {
    LDLT<SquareMatrixType,Lower> ldltlo(symmLo);
    VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix());
    vecX = ldltlo.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = ldltlo.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

    LDLT<SquareMatrixType,Upper> ldltup(symmUp);
    VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix());
    vecX = ldltup.solve(vecB);
    VERIFY_IS_APPROX(symm * vecX, vecB);
    matX = ldltup.solve(matB);
    VERIFY_IS_APPROX(symm * matX, matB);

//     if(MatrixType::RowsAtCompileTime==Dynamic)
//     {
//       // note : each inplace permutation requires a small temporary vector (mask)
//
//       // check inplace solve
//       matX = matB;
//       VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0);
//       VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval());
//
//
//       matX = matB;
//       VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0);
//       VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval());
//     }
  }

}

template<typename MatrixType> void cholesky_verify_assert()
{
  MatrixType tmp;

  LLT<MatrixType> llt;
  VERIFY_RAISES_ASSERT(llt.matrixL())
  VERIFY_RAISES_ASSERT(llt.matrixU())
  VERIFY_RAISES_ASSERT(llt.solve(tmp))
  VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp))

  LDLT<MatrixType> ldlt;
  VERIFY_RAISES_ASSERT(ldlt.matrixL())
  VERIFY_RAISES_ASSERT(ldlt.permutationP())
  VERIFY_RAISES_ASSERT(ldlt.vectorD())
  VERIFY_RAISES_ASSERT(ldlt.isPositive())
  VERIFY_RAISES_ASSERT(ldlt.isNegative())
  VERIFY_RAISES_ASSERT(ldlt.solve(tmp))
  VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp))
}

void test_cholesky()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) );
    CALL_SUBTEST_2( cholesky(MatrixXd(1,1)) );
    CALL_SUBTEST_3( cholesky(Matrix2d()) );
    CALL_SUBTEST_4( cholesky(Matrix3f()) );
    CALL_SUBTEST_5( cholesky(Matrix4d()) );
    CALL_SUBTEST_2( cholesky(MatrixXd(200,200)) );
    CALL_SUBTEST_6( cholesky(MatrixXcd(100,100)) );
  }

  CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() );
  CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() );
  CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() );
  CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() );

  // Test problem size constructors
  CALL_SUBTEST_9( LLT<MatrixXf>(10) );
  CALL_SUBTEST_9( LDLT<MatrixXf>(10) );
}
<|endoftext|>


<commit_before>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hook_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0),
      m_option_manager(GlobalOptionManager::instance())
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHookManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHookManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    BufferManager::instance().unregister_buffer(this);
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    return BufferIterator(*this, clamp(line_and_column));
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    return iterator.m_coord;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    return iterator.line();
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(line < line_count());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1].start : length();
    return end - m_lines[line].start;
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line) - 2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, { iterator.line(), 0 });
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = iterator.line();
    return ++BufferIterator(*this, { line, std::max(line_length(line) - 1, 0) });
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, { 0, 0 });
}

BufferIterator Buffer::end() const
{
    if (m_lines.empty())
        return BufferIterator(*this, { 0, 0 });
    return BufferIterator(*this, { (int)line_count()-1, (int)m_lines.back().length() });
}

BufferSize Buffer::length() const
{
    if (m_lines.empty())
        return 0;
    return m_lines.back().start + m_lines.back().length();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    String res;
    for (BufferPos line = begin.line(); line <= end.line(); ++line)
    {
       size_t start = 0;
       if (line == begin.line())
           start = begin.column();
       size_t count = -1;
       if (line == end.line())
           count = end.column() - start;
       res += m_lines[line].content.substr(start, count);
    }
    return res;
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::check_invariant() const
{
    BufferSize start = 0;
    for (auto& line : m_lines)
    {
        assert(line.start == start);
        start += line.length();
    }
}

void Buffer::insert(const BufferIterator& pos, const String& content)
{
    BufferSize offset = pos.offset();

    // all following lines advanced by length
    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start += content.length();

    // if we inserted at the end of the buffer, we may have created a new
    // line without inserting a '\n'
    if (pos == end() and (pos == begin() or *(pos-1) == '\n'))
    {
        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                m_lines.push_back({ offset + start, content.substr(start, i + 1 - start) });
                start = i + 1;
            }
        }
        if (start != content.length())
            m_lines.push_back({ offset + start, content.substr(start) });
    }
    else
    {
        String prefix = m_lines[pos.line()].content.substr(0, pos.column());
        String suffix = m_lines[pos.line()].content.substr(pos.column());

        auto line_it = m_lines.begin() + pos.line();
        line_it = m_lines.erase(line_it);

        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                String line_content = content.substr(start, i + 1 - start);
                if (start == 0)
                {
                    line_content = prefix + line_content;
                    line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(),
                                                        std::move(line_content) });
                }
                else
                    line_it = m_lines.insert(line_it, { offset + start,
                                                        std::move(line_content) });

                ++line_it;
                start = i + 1;
            }
        }
        if (start == 0)
            m_lines.insert(line_it, { offset + start - (int)prefix.length(), prefix + content + suffix });
        else
            m_lines.insert(line_it, { offset + start, content.substr(start) + suffix });
    }

    check_invariant();
}

void Buffer::erase(const BufferIterator& pos, BufferSize length)
{
    BufferIterator end = pos + length;
    String prefix = m_lines[pos.line()].content.substr(0, pos.column());
    String suffix = m_lines[end.line()].content.substr(end.column());
    Line new_line = { m_lines[pos.line()].start, prefix + suffix };

    m_lines.erase(m_lines.begin() + pos.line(), m_lines.begin() + end.line() + 1);
    m_lines.insert(m_lines.begin() + pos.line(), new_line);

    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start -= length;

    check_invariant();
}

void Buffer::apply_modification(const Modification& modification)
{
    const String& content = modification.content;
    const BufferIterator& pos = modification.position;

    switch (modification.type)
    {
    case Modification::Insert:
        insert(modification.position, modification.content);
        break;
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        erase(modification.position, size);
        break;
    }
    default:
        assert(false);
    }

    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<commit_msg>fix some corner cases in Buffer modification<commit_after>#include "buffer.hh"

#include "buffer_manager.hh"
#include "window.hh"
#include "assert.hh"
#include "utils.hh"
#include "hook_manager.hh"
#include "context.hh"

#include <algorithm>

namespace Kakoune
{

template<typename T>
T clamp(T min, T max, T val)
{
    if (val < min)
        return min;
    if (val > max)
        return max;
    return val;
}

Buffer::Buffer(const std::string& name, Type type,
               const String& initial_content)
    : m_name(name), m_type(type),
      m_history(1), m_history_cursor(m_history.begin()),
      m_last_save_undo_index(0),
      m_option_manager(GlobalOptionManager::instance())
{
    BufferManager::instance().register_buffer(this);
    if (not initial_content.empty())
        apply_modification(Modification::make_insert(begin(), initial_content));

    if (type == Type::NewFile)
        GlobalHookManager::instance().run_hook("BufCreate", name, Context(*this));
    else if (type == Type::File)
        GlobalHookManager::instance().run_hook("BufOpen", name, Context(*this));
}

Buffer::~Buffer()
{
    m_windows.clear();
    BufferManager::instance().unregister_buffer(this);
    assert(m_modification_listeners.empty());
}

BufferIterator Buffer::iterator_at(const BufferCoord& line_and_column) const
{
    return BufferIterator(*this, clamp(line_and_column));
}

BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
{
    return iterator.m_coord;
}

BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
    return iterator.line();
}

BufferSize Buffer::line_length(BufferPos line) const
{
    assert(line < line_count());
    BufferPos end = (line < m_lines.size() - 1) ?
                    m_lines[line + 1].start : length();
    return end - m_lines[line].start;
}

BufferCoord Buffer::clamp(const BufferCoord& line_and_column) const
{
    if (m_lines.empty())
        return BufferCoord();

    BufferCoord result(line_and_column.line, line_and_column.column);
    result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
    int max_col = std::max(0, line_length(result.line) - 2);
    result.column = Kakoune::clamp<int>(0, max_col, result.column);
    return result;
}

BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) const
{
    return BufferIterator(*this, { iterator.line(), 0 });
}

BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
    BufferPos line = iterator.line();
    return ++BufferIterator(*this, { line, std::max(line_length(line) - 1, 0) });
}

BufferIterator Buffer::begin() const
{
    return BufferIterator(*this, { 0, 0 });
}

BufferIterator Buffer::end() const
{
    if (m_lines.empty())
        return BufferIterator(*this, { 0, 0 });
    return BufferIterator(*this, { (int)line_count()-1, (int)m_lines.back().length() });
}

BufferSize Buffer::length() const
{
    if (m_lines.empty())
        return 0;
    return m_lines.back().start + m_lines.back().length();
}

BufferSize Buffer::line_count() const
{
    return m_lines.size();
}

String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
    String res;
    for (BufferPos line = begin.line(); line <= end.line(); ++line)
    {
       size_t start = 0;
       if (line == begin.line())
           start = begin.column();
       size_t count = -1;
       if (line == end.line())
           count = end.column() - start;
       res += m_lines[line].content.substr(start, count);
    }
    return res;
}

void Buffer::begin_undo_group()
{
    assert(m_current_undo_group.empty());
    m_history.erase(m_history_cursor, m_history.end());

    if (m_history.size() < m_last_save_undo_index)
        m_last_save_undo_index = -1;

    m_history_cursor = m_history.end();
}

void Buffer::end_undo_group()
{
    m_history.push_back(m_current_undo_group);
    m_history_cursor = m_history.end();

    m_current_undo_group.clear();
}

Modification Modification::inverse() const
{
    Type inverse_type;
    switch (type)
    {
    case Insert: inverse_type = Erase;  break;
    case Erase:  inverse_type = Insert; break;
    default: assert(false);
    }
    return Modification(inverse_type, position, content);
}

bool Buffer::undo()
{
    if (m_history_cursor == m_history.begin())
        return false;

    --m_history_cursor;

    for (const Modification& modification : reversed(*m_history_cursor))
        apply_modification(modification.inverse());
}

bool Buffer::redo()
{
    if (m_history_cursor == m_history.end())
        return false;

    for (const Modification& modification : *m_history_cursor)
        apply_modification(modification);

    ++m_history_cursor;
}

void Buffer::check_invariant() const
{
    BufferSize start = 0;
    for (auto& line : m_lines)
    {
        assert(line.start == start);
        assert(line.length() > 0);
        start += line.length();
    }
}

void Buffer::insert(const BufferIterator& pos, const String& content)
{
    BufferSize offset = pos.offset();

    // all following lines advanced by length
    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start += content.length();

    // if we inserted at the end of the buffer, we may have created a new
    // line without inserting a '\n'
    if (pos == end() and (pos == begin() or *(pos-1) == '\n'))
    {
        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                m_lines.push_back({ offset + start, content.substr(start, i + 1 - start) });
                start = i + 1;
            }
        }
        if (start != content.length())
            m_lines.push_back({ offset + start, content.substr(start) });
    }
    else
    {
        String prefix = m_lines[pos.line()].content.substr(0, pos.column());
        String suffix = m_lines[pos.line()].content.substr(pos.column());

        auto line_it = m_lines.begin() + pos.line();
        line_it = m_lines.erase(line_it);

        int start = 0;
        for (int i = 0; i < content.length(); ++i)
        {
            if (content[i] == '\n')
            {
                String line_content = content.substr(start, i + 1 - start);
                if (start == 0)
                {
                    line_content = prefix + line_content;
                    line_it = m_lines.insert(line_it, { offset + start - (int)prefix.length(),
                                                        std::move(line_content) });
                }
                else
                    line_it = m_lines.insert(line_it, { offset + start,
                                                        std::move(line_content) });

                ++line_it;
                start = i + 1;
            }
        }
        if (start == 0)
            m_lines.insert(line_it, { offset + start - (int)prefix.length(), prefix + content + suffix });
        else
            m_lines.insert(line_it, { offset + start, content.substr(start) + suffix });
    }

    check_invariant();
}

void Buffer::erase(const BufferIterator& pos, BufferSize length)
{
    BufferIterator end = pos + length;
    String prefix = m_lines[pos.line()].content.substr(0, pos.column());
    String suffix = m_lines[end.line()].content.substr(end.column());
    Line new_line = { m_lines[pos.line()].start, prefix + suffix };

    m_lines.erase(m_lines.begin() + pos.line(), m_lines.begin() + end.line() + 1);
    if (new_line.length())
        m_lines.insert(m_lines.begin() + pos.line(), std::move(new_line));

    for (size_t i = pos.line()+1; i < line_count(); ++i)
        m_lines[i].start -= length;

    check_invariant();
}

void Buffer::apply_modification(const Modification& modification)
{
    const String& content = modification.content;
    const BufferIterator& pos = modification.position;

    switch (modification.type)
    {
    case Modification::Insert:
    {
        BufferIterator pos = modification.position < end() ?
                             modification.position : end();
        insert(pos, modification.content);
        break;
    }
    case Modification::Erase:
    {
        size_t size = modification.content.size();
        assert(string(modification.position, modification.position + size)
               == modification.content);
        erase(modification.position, size);
        break;
    }
    default:
        assert(false);
    }

    for (auto listener : m_modification_listeners)
        listener->on_modification(modification);
}

void Buffer::modify(Modification&& modification)
{
    if (modification.content.empty())
        return;

    apply_modification(modification);
    m_current_undo_group.push_back(std::move(modification));
}

Window* Buffer::get_or_create_window()
{
    if (m_windows.empty())
        m_windows.push_front(std::unique_ptr<Window>(new Window(*this)));

    return m_windows.front().get();
}

void Buffer::delete_window(Window* window)
{
    assert(&window->buffer() == this);
    auto window_it = std::find(m_windows.begin(), m_windows.end(), window);
    assert(window_it != m_windows.end());
    m_windows.erase(window_it);
}

bool Buffer::is_modified() const
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    return m_last_save_undo_index != history_cursor_index
           or not m_current_undo_group.empty();
}

void Buffer::notify_saved()
{
    size_t history_cursor_index = m_history_cursor - m_history.begin();
    m_last_save_undo_index = history_cursor_index;
}

void Buffer::register_modification_listener(ModificationListener* listener)
{
    assert(listener);
    assert(not contains(m_modification_listeners, listener));
    m_modification_listeners.push_back(listener);
}

void Buffer::unregister_modification_listener(ModificationListener* listener)
{
    assert(listener);
    auto it = std::find(m_modification_listeners.begin(),
                        m_modification_listeners.end(),
                        listener);
    assert(it != m_modification_listeners.end());
    m_modification_listeners.erase(it);
}

}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Elisavet Sakellari <elisavet.sakellari@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ExternalInterpreterSource.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTImporter.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace {
  class ClingASTImporter : public ASTImporter {
  private:
    cling::ExternalInterpreterSource &m_Source;

  public:
    ClingASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
                     ASTContext &FromContext, FileManager &FromFileManager,
                     bool MinimalImport, cling::ExternalInterpreterSource& source):
      ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
                  MinimalImport), m_Source(source) {}
    virtual ~ClingASTImporter() = default;

    Decl *Imported(Decl *From, Decl *To) override {
      ASTImporter::Imported(From, To);

      if (clang::TagDecl* toTagDecl = dyn_cast<TagDecl>(To)) {
        toTagDecl->setHasExternalLexicalStorage();
        toTagDecl->setMustBuildLookupTable();
        toTagDecl->setHasExternalVisibleStorage();
      }
      if (NamespaceDecl *toNamespaceDecl = dyn_cast<NamespaceDecl>(To)) {
        toNamespaceDecl->setHasExternalVisibleStorage();
      }
      if (ObjCContainerDecl *toContainerDecl = dyn_cast<ObjCContainerDecl>(To)) {
        toContainerDecl->setHasExternalLexicalStorage();
        toContainerDecl->setHasExternalVisibleStorage();
      }
      // Put the name of the Decl imported with the
      // DeclarationName coming from the parent, in  my map.
      if (NamedDecl *toNamedDecl = llvm::dyn_cast<NamedDecl>(To)) {
        m_Source.addToImportedDecls(toNamedDecl->getDeclName(),
                                    fromNamedDecl->getDeclName());
      }
      if (DeclContext *toDeclContext = llvm::dyn_cast<DeclContext>(To)) {
        m_Source.addToImportedDeclContexts(toDeclContext, fromDeclContext);
      }
      return To;
    }
  };
}

namespace cling {

  ExternalInterpreterSource::ExternalInterpreterSource(
          const cling::Interpreter *parent, cling::Interpreter *child) :
          m_ParentInterpreter(parent), m_ChildInterpreter(child) {

    clang::DeclContext *parentTUDeclContext =
      m_ParentInterpreter->getCI()->getASTContext().getTranslationUnitDecl();

    clang::DeclContext *childTUDeclContext =
      m_ChildInterpreter->getCI()->getASTContext().getTranslationUnitDecl();

    // Also keep in the map of Decl Contexts the Translation Unit Decl Context
    m_ImportedDeclContexts[childTUDeclContext] = parentTUDeclContext;
  }

  ExternalInterpreterSource::~ExternalInterpreterSource() {}

  ClingASTImporter CreateClingASTImporter(ASTContext &toContext,
                                          ASTContext &fromContext,
                                          const Interpreter* child,
                                          const Interpreter* parent,
                                          ExternalInterpreterSource& source) {

    FileManager &childFM = child->getCI()->getFileManager();
    FileManager &parentFM = parent->getCI()->getFileManager();

    return ClingASTImporter(toContext, childFM, fromContext, parentFM,
                            /*MinimalImport : ON*/ true, source);
  }

  void ExternalInterpreterSource::ImportDecl(Decl *declToImport,
                                   ASTImporter &importer,
                                   DeclarationName &childDeclName,
                                   DeclarationName &parentDeclName,
                                   const DeclContext *childCurrentDeclContext) {

    // Don't do the import if we have a Function Template.
    // Not supported by clang.
    // FIXME: This is also a temporary check. Will be de-activated
    // once clang supports the import of function templates.
    if (declToImport->isFunctionOrFunctionTemplate()
        && declToImport->isTemplateDecl())
      return;

    if (Decl *importedDecl = importer.Import(declToImport)) {
      if (NamedDecl *importedNamedDecl = llvm::dyn_cast<NamedDecl>(importedDecl)) {
        SetExternalVisibleDeclsForName(childCurrentDeclContext,
                                       importedNamedDecl->getDeclName(),
                                       importedNamedDecl);
      }
      // Put the name of the Decl imported with the
      // DeclarationName coming from the parent, in  my map.
      m_ImportedDecls[childDeclName] = parentDeclName;
    }
  }

  void ExternalInterpreterSource::ImportDeclContext(
                                  DeclContext *declContextToImport,
                                  ASTImporter &importer,
                                  DeclarationName &childDeclName,
                                  DeclarationName &parentDeclName,
                                  const DeclContext *childCurrentDeclContext) {

    if (DeclContext *importedDeclContext =
                                importer.ImportContext(declContextToImport)) {

      importedDeclContext->setHasExternalVisibleStorage(true);
      if (NamedDecl *importedNamedDecl =
                            llvm::dyn_cast<NamedDecl>(importedDeclContext)) {
        SetExternalVisibleDeclsForName(childCurrentDeclContext,
                                       importedNamedDecl->getDeclName(),
                                       importedNamedDecl);
      }

      // Put the name of the DeclContext imported with the
      // DeclarationName coming from the parent, in  my map.
      m_ImportedDecls[childDeclName] = parentDeclName;

      // And also put the declaration context I found from the parent Interpreter
      // in the map of the child Interpreter to have it for the future.
      m_ImportedDeclContexts[importedDeclContext] = declContextToImport;
    }
  }

  bool ExternalInterpreterSource::Import(DeclContext::lookup_result lookup_result,
                                ASTContext &fromASTContext,
                                ASTContext &toASTContext,
                                const DeclContext *childCurrentDeclContext,
                                DeclarationName &childDeclName,
                                DeclarationName &parentDeclName) {

    // Cling's ASTImporter
    ClingASTImporter importer = CreateClingASTImporter(toASTContext,
                                                       fromASTContext,
                                                       m_ChildInterpreter,
                                                       m_ParentInterpreter,
                                                       *this);

    for (DeclContext::lookup_iterator I = lookup_result.begin(),
          E = lookup_result.end(); I != E; ++I) {
      // Check if this Name we are looking for is
      // a DeclContext (for example a Namespace, function etc.).
      if (DeclContext *declContextToImport = llvm::dyn_cast<DeclContext>(*I)) {

        ImportDeclContext(declContextToImport, importer, childDeclName,
                          parentDeclName, childCurrentDeclContext);

      }
      ImportDecl(*I, importer, childDeclName, parentDeclName,
                 childCurrentDeclContext);
    }
    return true;
  }

  ///\brief This is the one of the most important function of the class
  /// since from here initiates the lookup and import part of the missing
  /// Decl(s) (Contexts).
  ///
  bool ExternalInterpreterSource::FindExternalVisibleDeclsByName(
    const DeclContext *childCurrentDeclContext, DeclarationName childDeclName) {

    assert(childDeclName && "Child Decl name is empty");

    assert(childCurrentDeclContext->hasExternalVisibleStorage() &&
           "DeclContext has no visible decls in storage");

    //Check if we have already found this declaration Name before
    DeclarationName parentDeclName;
    std::map<clang::DeclarationName,
             clang::DeclarationName>::iterator IDecl =
                                            m_ImportedDecls.find(childDeclName);
    if (IDecl != m_ImportedDecls.end()) {
      parentDeclName = IDecl->second;
    } else {
      // Get the identifier info from the parent interpreter
      // for this Name.
      std::string name = childDeclName.getAsString();
      IdentifierTable &parentIdentifierTable =
                            m_ParentInterpreter->getCI()->getASTContext().Idents;
      IdentifierInfo &parentIdentifierInfo =
                            parentIdentifierTable.get(name);
      parentDeclName = DeclarationName(&parentIdentifierInfo);
    }

    // Search in the map of the stored Decl Contexts for this
    // Decl Context.
    std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
          IDeclContext = m_ImportedDeclContexts.find(childCurrentDeclContext);
    // If childCurrentDeclContext was found before and is already in the map,
    // then do the lookup using the stored pointer.
    if (IDeclContext == m_ImportedDeclContexts.end()) return false;

    DeclContext *parentDeclContext = IDeclContext->second;

    DeclContext::lookup_result lookup_result =
                                    parentDeclContext->lookup(parentDeclName);

    // Check if we found this Name in the parent interpreter
    if (!lookup_result.empty()) {
      ASTContext &fromASTContext =
            Decl::castFromDeclContext(parentDeclContext)->getASTContext();
      ASTContext &toASTContext =
            Decl::castFromDeclContext(childCurrentDeclContext)->getASTContext();
      if (Import(lookup_result, fromASTContext, toASTContext,
                 childCurrentDeclContext, childDeclName, parentDeclName))
        return true;
    }

    return false;
  }

  ///\brief Make available to child all decls in parent's decl context
  /// that corresponds to child decl context.
  void ExternalInterpreterSource::completeVisibleDeclsMap(
                                const clang::DeclContext *childDeclContext) {
    assert (childDeclContext && "No child decl context!");

    if (!childDeclContext->hasExternalVisibleStorage())
      return;

    // Search in the map of the stored Decl Contexts for this
    // Decl Context.
    std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
                  IDeclContext = m_ImportedDeclContexts.find(childDeclContext);
    // If childCurrentDeclContext was found before and is already in the map,
    // then do the lookup using the stored pointer.
    if (IDeclContext == m_ImportedDeclContexts.end()) return ;

    DeclContext *parentDeclContext = IDeclContext->second;

    ASTContext &fromASTContext =
          Decl::castFromDeclContext(parentDeclContext)->getASTContext();
    ASTContext &toASTContext =
          Decl::castFromDeclContext(childDeclContext)->getASTContext();

    // Cling's ASTImporter
    ClingASTImporter importer = CreateClingASTImporter(toASTContext,
                                                       fromASTContext,
                                                       m_ChildInterpreter,
                                                       m_ParentInterpreter,
                                                       *this);

    // Filter the decls from the external source using the stem information
    // stored in Sema.
    StringRef filter =
      m_ChildInterpreter->getCI()->getPreprocessor().getCodeCompletionFilter();
    for (DeclContext::decl_iterator IDeclContext =
                                      parentDeclContext->decls_begin(),
                                    EDeclContext =
                                      parentDeclContext->decls_end();
                              IDeclContext != EDeclContext; ++IDeclContext) {
      if (NamedDecl* parentDecl = llvm::dyn_cast<NamedDecl>(*IDeclContext)) {
        DeclarationName childDeclName = parentDecl->getDeclName();
        if (auto II = childDeclName.getAsIdentifierInfo()) {
          StringRef name = II->getName();
          if (!name.empty() && name.startswith(filter))
            ImportDecl(parentDecl, importer, childDeclName, childDeclName,
                       childDeclContext);
        }
      }
    }

    const_cast<DeclContext *>(childDeclContext)->
                                      setHasExternalVisibleStorage(false);
  }
} // end namespace cling
<commit_msg>Fix compilation failure. From Cristina.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author:  Elisavet Sakellari <elisavet.sakellari@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------

#include "ExternalInterpreterSource.h"
#include "cling/Interpreter/Interpreter.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTImporter.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"

using namespace clang;

namespace {
  class ClingASTImporter : public ASTImporter {
  private:
    cling::ExternalInterpreterSource &m_Source;

  public:
    ClingASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
                     ASTContext &FromContext, FileManager &FromFileManager,
                     bool MinimalImport, cling::ExternalInterpreterSource& source):
      ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
                  MinimalImport), m_Source(source) {}
    virtual ~ClingASTImporter() = default;

    Decl *Imported(Decl *From, Decl *To) override {
      ASTImporter::Imported(From, To);

      if (clang::TagDecl* toTagDecl = dyn_cast<TagDecl>(To)) {
        toTagDecl->setHasExternalLexicalStorage();
        toTagDecl->setMustBuildLookupTable();
        toTagDecl->setHasExternalVisibleStorage();
      }
      if (NamespaceDecl *toNamespaceDecl = dyn_cast<NamespaceDecl>(To)) {
        toNamespaceDecl->setHasExternalVisibleStorage();
      }
      if (ObjCContainerDecl *toContainerDecl = dyn_cast<ObjCContainerDecl>(To)) {
        toContainerDecl->setHasExternalLexicalStorage();
        toContainerDecl->setHasExternalVisibleStorage();
      }
      // Put the name of the Decl imported with the
      // DeclarationName coming from the parent, in  my map.
      if (NamedDecl *toNamedDecl = llvm::dyn_cast<NamedDecl>(To)) {
        NamedDecl *fromNamedDecl = llvm::dyn_cast<NamedDecl>(From);
        m_Source.addToImportedDecls(toNamedDecl->getDeclName(),
                                    fromNamedDecl->getDeclName());
      }
      if (DeclContext *toDeclContext = llvm::dyn_cast<DeclContext>(To)) {
        DeclContext *fromDeclContext = llvm::dyn_cast<DeclContext>(From);
        m_Source.addToImportedDeclContexts(toDeclContext, fromDeclContext);
      }
      return To;
    }
  };
}

namespace cling {

  ExternalInterpreterSource::ExternalInterpreterSource(
          const cling::Interpreter *parent, cling::Interpreter *child) :
          m_ParentInterpreter(parent), m_ChildInterpreter(child) {

    clang::DeclContext *parentTUDeclContext =
      m_ParentInterpreter->getCI()->getASTContext().getTranslationUnitDecl();

    clang::DeclContext *childTUDeclContext =
      m_ChildInterpreter->getCI()->getASTContext().getTranslationUnitDecl();

    // Also keep in the map of Decl Contexts the Translation Unit Decl Context
    m_ImportedDeclContexts[childTUDeclContext] = parentTUDeclContext;
  }

  ExternalInterpreterSource::~ExternalInterpreterSource() {}

  ClingASTImporter CreateClingASTImporter(ASTContext &toContext,
                                          ASTContext &fromContext,
                                          const Interpreter* child,
                                          const Interpreter* parent,
                                          ExternalInterpreterSource& source) {

    FileManager &childFM = child->getCI()->getFileManager();
    FileManager &parentFM = parent->getCI()->getFileManager();

    return ClingASTImporter(toContext, childFM, fromContext, parentFM,
                            /*MinimalImport : ON*/ true, source);
  }

  void ExternalInterpreterSource::ImportDecl(Decl *declToImport,
                                   ASTImporter &importer,
                                   DeclarationName &childDeclName,
                                   DeclarationName &parentDeclName,
                                   const DeclContext *childCurrentDeclContext) {

    // Don't do the import if we have a Function Template.
    // Not supported by clang.
    // FIXME: This is also a temporary check. Will be de-activated
    // once clang supports the import of function templates.
    if (declToImport->isFunctionOrFunctionTemplate()
        && declToImport->isTemplateDecl())
      return;

    if (Decl *importedDecl = importer.Import(declToImport)) {
      if (NamedDecl *importedNamedDecl = llvm::dyn_cast<NamedDecl>(importedDecl)) {
        SetExternalVisibleDeclsForName(childCurrentDeclContext,
                                       importedNamedDecl->getDeclName(),
                                       importedNamedDecl);
      }
      // Put the name of the Decl imported with the
      // DeclarationName coming from the parent, in  my map.
      m_ImportedDecls[childDeclName] = parentDeclName;
    }
  }

  void ExternalInterpreterSource::ImportDeclContext(
                                  DeclContext *declContextToImport,
                                  ASTImporter &importer,
                                  DeclarationName &childDeclName,
                                  DeclarationName &parentDeclName,
                                  const DeclContext *childCurrentDeclContext) {

    if (DeclContext *importedDeclContext =
                                importer.ImportContext(declContextToImport)) {

      importedDeclContext->setHasExternalVisibleStorage(true);
      if (NamedDecl *importedNamedDecl =
                            llvm::dyn_cast<NamedDecl>(importedDeclContext)) {
        SetExternalVisibleDeclsForName(childCurrentDeclContext,
                                       importedNamedDecl->getDeclName(),
                                       importedNamedDecl);
      }

      // Put the name of the DeclContext imported with the
      // DeclarationName coming from the parent, in  my map.
      m_ImportedDecls[childDeclName] = parentDeclName;

      // And also put the declaration context I found from the parent Interpreter
      // in the map of the child Interpreter to have it for the future.
      m_ImportedDeclContexts[importedDeclContext] = declContextToImport;
    }
  }

  bool ExternalInterpreterSource::Import(DeclContext::lookup_result lookup_result,
                                ASTContext &fromASTContext,
                                ASTContext &toASTContext,
                                const DeclContext *childCurrentDeclContext,
                                DeclarationName &childDeclName,
                                DeclarationName &parentDeclName) {

    // Cling's ASTImporter
    ClingASTImporter importer = CreateClingASTImporter(toASTContext,
                                                       fromASTContext,
                                                       m_ChildInterpreter,
                                                       m_ParentInterpreter,
                                                       *this);

    for (DeclContext::lookup_iterator I = lookup_result.begin(),
          E = lookup_result.end(); I != E; ++I) {
      // Check if this Name we are looking for is
      // a DeclContext (for example a Namespace, function etc.).
      if (DeclContext *declContextToImport = llvm::dyn_cast<DeclContext>(*I)) {

        ImportDeclContext(declContextToImport, importer, childDeclName,
                          parentDeclName, childCurrentDeclContext);

      }
      ImportDecl(*I, importer, childDeclName, parentDeclName,
                 childCurrentDeclContext);
    }
    return true;
  }

  ///\brief This is the one of the most important function of the class
  /// since from here initiates the lookup and import part of the missing
  /// Decl(s) (Contexts).
  ///
  bool ExternalInterpreterSource::FindExternalVisibleDeclsByName(
    const DeclContext *childCurrentDeclContext, DeclarationName childDeclName) {

    assert(childDeclName && "Child Decl name is empty");

    assert(childCurrentDeclContext->hasExternalVisibleStorage() &&
           "DeclContext has no visible decls in storage");

    //Check if we have already found this declaration Name before
    DeclarationName parentDeclName;
    std::map<clang::DeclarationName,
             clang::DeclarationName>::iterator IDecl =
                                            m_ImportedDecls.find(childDeclName);
    if (IDecl != m_ImportedDecls.end()) {
      parentDeclName = IDecl->second;
    } else {
      // Get the identifier info from the parent interpreter
      // for this Name.
      std::string name = childDeclName.getAsString();
      IdentifierTable &parentIdentifierTable =
                            m_ParentInterpreter->getCI()->getASTContext().Idents;
      IdentifierInfo &parentIdentifierInfo =
                            parentIdentifierTable.get(name);
      parentDeclName = DeclarationName(&parentIdentifierInfo);
    }

    // Search in the map of the stored Decl Contexts for this
    // Decl Context.
    std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
          IDeclContext = m_ImportedDeclContexts.find(childCurrentDeclContext);
    // If childCurrentDeclContext was found before and is already in the map,
    // then do the lookup using the stored pointer.
    if (IDeclContext == m_ImportedDeclContexts.end()) return false;

    DeclContext *parentDeclContext = IDeclContext->second;

    DeclContext::lookup_result lookup_result =
                                    parentDeclContext->lookup(parentDeclName);

    // Check if we found this Name in the parent interpreter
    if (!lookup_result.empty()) {
      ASTContext &fromASTContext =
            Decl::castFromDeclContext(parentDeclContext)->getASTContext();
      ASTContext &toASTContext =
            Decl::castFromDeclContext(childCurrentDeclContext)->getASTContext();
      if (Import(lookup_result, fromASTContext, toASTContext,
                 childCurrentDeclContext, childDeclName, parentDeclName))
        return true;
    }

    return false;
  }

  ///\brief Make available to child all decls in parent's decl context
  /// that corresponds to child decl context.
  void ExternalInterpreterSource::completeVisibleDeclsMap(
                                const clang::DeclContext *childDeclContext) {
    assert (childDeclContext && "No child decl context!");

    if (!childDeclContext->hasExternalVisibleStorage())
      return;

    // Search in the map of the stored Decl Contexts for this
    // Decl Context.
    std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
                  IDeclContext = m_ImportedDeclContexts.find(childDeclContext);
    // If childCurrentDeclContext was found before and is already in the map,
    // then do the lookup using the stored pointer.
    if (IDeclContext == m_ImportedDeclContexts.end()) return ;

    DeclContext *parentDeclContext = IDeclContext->second;

    ASTContext &fromASTContext =
          Decl::castFromDeclContext(parentDeclContext)->getASTContext();
    ASTContext &toASTContext =
          Decl::castFromDeclContext(childDeclContext)->getASTContext();

    // Cling's ASTImporter
    ClingASTImporter importer = CreateClingASTImporter(toASTContext,
                                                       fromASTContext,
                                                       m_ChildInterpreter,
                                                       m_ParentInterpreter,
                                                       *this);

    // Filter the decls from the external source using the stem information
    // stored in Sema.
    StringRef filter =
      m_ChildInterpreter->getCI()->getPreprocessor().getCodeCompletionFilter();
    for (DeclContext::decl_iterator IDeclContext =
                                      parentDeclContext->decls_begin(),
                                    EDeclContext =
                                      parentDeclContext->decls_end();
                              IDeclContext != EDeclContext; ++IDeclContext) {
      if (NamedDecl* parentDecl = llvm::dyn_cast<NamedDecl>(*IDeclContext)) {
        DeclarationName childDeclName = parentDecl->getDeclName();
        if (auto II = childDeclName.getAsIdentifierInfo()) {
          StringRef name = II->getName();
          if (!name.empty() && name.startswith(filter))
            ImportDecl(parentDecl, importer, childDeclName, childDeclName,
                       childDeclContext);
        }
      }
    }

    const_cast<DeclContext *>(childDeclContext)->
                                      setHasExternalVisibleStorage(false);
  }
} // end namespace cling
<|endoftext|>