<commit_before>#include "display_buffer.hh"

#include "assert.hh"
#include "buffer.hh"
#include "buffer_utils.hh"
#include "utf8.hh"

#include "face_registry.hh"

namespace Kakoune
{

BufferIterator get_iterator(const Buffer& buffer, BufferCoord coord)
{
    // Correct one past the end of line as next line
    if (not buffer.is_end(coord) and coord.column == buffer[coord.line].length())
        coord = coord.line+1;
    return buffer.iterator_at(coord);
}

StringView DisplayAtom::content() const
{
    switch (m_type)
    {
        case Range:
        {
            auto line = (*m_buffer)[m_range.begin.line];
            if (m_range.begin.line == m_range.end.line)
                return line.substr(m_range.begin.column, m_range.end.column - m_range.begin.column);
            else if (m_range.begin.line+1 == m_range.end.line and m_range.end.column == 0)
                return line.substr(m_range.begin.column);
            break;
        }
        case Text:
        case ReplacedRange:
            return m_text;
    }
    kak_assert(false);
    return {};
}

ColumnCount DisplayAtom::length() const
{
    switch (m_type)
    {
        case Range:
            return utf8::column_distance(get_iterator(*m_buffer, m_range.begin),
                                         get_iterator(*m_buffer, m_range.end));
        case Text:
        case ReplacedRange:
            return m_text.column_length();
    }
    kak_assert(false);
    return 0;
}

void DisplayAtom::trim_begin(ColumnCount count)
{
    if (m_type == Range)
        m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin),
                                      get_iterator(*m_buffer, m_range.end),
                                      count).coord();
    else
        m_text = m_text.substr(count).str();
}

void DisplayAtom::trim_end(ColumnCount count)
{
    if (m_type == Range)
        m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end),
                                    get_iterator(*m_buffer, m_range.begin),
                                    -count).coord();
    else
        m_text = m_text.substr(0, m_text.column_length() - count).str();
}

DisplayLine::DisplayLine(AtomList atoms)
    : m_atoms(std::move(atoms))
{
    compute_range();
}

DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos)
{
    kak_assert(it->type() == DisplayAtom::Range);
    kak_assert(it->begin() < pos);
    kak_assert(it->end() > pos);

    DisplayAtom atom = *it;
    atom.m_range.end = pos;
    it->m_range.begin = pos;
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount pos)
{
    kak_assert(it->type() == DisplayAtom::Text);
    kak_assert(pos > 0);
    kak_assert(pos < it->length());

    DisplayAtom atom(it->m_text.substr(0, pos).str());
    it->m_text = it->m_text.substr(pos).str();
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    return m_atoms.insert(it, std::move(atom));
}

void DisplayLine::push_back(DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    m_atoms.push_back(std::move(atom));
}

DisplayLine::iterator DisplayLine::erase(iterator beg, iterator end)
{
    auto res = m_atoms.erase(beg, end);
    compute_range();
    return res;
}

void DisplayLine::optimize()
{
    if (m_atoms.empty())
        return;

    auto atom_it = m_atoms.begin();
    auto next_atom_it = atom_it + 1;
    while (next_atom_it != m_atoms.end())
    {
        auto& atom = *atom_it;
        auto& next_atom = *next_atom_it;
        bool merged = false;

        if (atom.face == next_atom.face and
            atom.type() ==  next_atom.type())
        {
            auto type = atom.type();
            if ((type == DisplayAtom::Range or
                 type == DisplayAtom::ReplacedRange) and
                next_atom.begin() == atom.end())
            {
                atom.m_range.end = next_atom.end();
                if (type == DisplayAtom::ReplacedRange)
                    atom.m_text += next_atom.m_text;
                merged = true;
            }
            if (type == DisplayAtom::Text)
            {
                atom.m_text += next_atom.m_text;
                merged = true;
            }
        }
        if (merged)
            next_atom_it = m_atoms.erase(next_atom_it);
        else
            atom_it = next_atom_it++;
    }
}

ColumnCount DisplayLine::length() const
{
    ColumnCount len = 0;
    for (auto& atom : m_atoms)
        len += atom.length();
    return len;
}

void DisplayLine::trim(ColumnCount first_col, ColumnCount col_count)
{
    for (auto it = begin(); first_col > 0 and it != end(); )
    {
        auto len = it->length();
        if (len <= first_col)
        {
            m_atoms.erase(it);
            first_col -= len;
        }
        else
        {
            it->trim_begin(first_col);
            first_col = 0;
        }
    }
    auto it = begin();
    for (; it != end() and col_count > 0; ++it)
        col_count -= it->length();

    if (col_count < 0)
        (it-1)->trim_end(-col_count);
    m_atoms.erase(it, end());

    compute_range();
}

const BufferRange init_range{ {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };

void DisplayLine::compute_range()
{
    m_range = init_range;
    for (auto& atom : m_atoms)
    {
        if (not atom.has_buffer_range())
            continue;
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::compute_range()
{
    m_range = init_range;
    for (auto& line : m_lines)
    {
        m_range.begin  = std::min(line.range().begin, m_range.begin);
        m_range.end = std::max(line.range().end, m_range.end);
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::optimize()
{
    for (auto& line : m_lines)
        line.optimize();
}

DisplayLine parse_display_line(StringView line, const HashMap<String, DisplayLine>& builtins)
{
    DisplayLine res;
    bool was_antislash = false;
    auto pos = line.begin();
    String content;
    Face face;
    for (auto it = line.begin(), end = line.end(); it != end; ++it)
    {
        const char c = *it;
        if (c == '{')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                content.back() = '{';
                pos = it + 1;
            }
            else
            {
                content += StringView{pos, it};
                res.push_back({std::move(content), face});
                content.clear();
                auto closing = std::find(it+1, end, '}');
                if (closing == end)
                    throw runtime_error("unclosed face definition");
                if (*(it+1) == '{' and closing+1 != end and *(closing+1) == '}')
                {
                    auto builtin_it = builtins.find(StringView{it+2, closing});
                    if (builtin_it == builtins.end())
                        throw runtime_error(format("undefined atom {}", StringView{it+2, closing}));
                    for (auto& atom : builtin_it->value)
                        res.push_back(atom);
                    // closing is now at the first char of "}}", advance it to the second
                    ++closing;
                }
                else
                    face = get_face({it+1, closing});
                it = closing;
                pos = closing + 1;
            }
        }
        if (c == '\n') // line breaks are forbidden, replace with space
        {
            content += StringView{pos, it+1};
            content.back() = ' ';
            pos = it + 1;
        }

        if (c == '\\')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                pos = it + 1;
                was_antislash = false;
            }
            else
                was_antislash = true;
        }
        else
            was_antislash = false;
    }
    content += StringView{pos, line.end()};
    if (not content.empty())
        res.push_back({std::move(content), face});
    return res;
}

}
<commit_msg>Optimize DisplayBuffer::optimize()<commit_after>#include "display_buffer.hh"

#include "assert.hh"
#include "buffer.hh"
#include "buffer_utils.hh"
#include "utf8.hh"

#include "face_registry.hh"

namespace Kakoune
{

BufferIterator get_iterator(const Buffer& buffer, BufferCoord coord)
{
    // Correct one past the end of line as next line
    if (not buffer.is_end(coord) and coord.column == buffer[coord.line].length())
        coord = coord.line+1;
    return buffer.iterator_at(coord);
}

StringView DisplayAtom::content() const
{
    switch (m_type)
    {
        case Range:
        {
            auto line = (*m_buffer)[m_range.begin.line];
            if (m_range.begin.line == m_range.end.line)
                return line.substr(m_range.begin.column, m_range.end.column - m_range.begin.column);
            else if (m_range.begin.line+1 == m_range.end.line and m_range.end.column == 0)
                return line.substr(m_range.begin.column);
            break;
        }
        case Text:
        case ReplacedRange:
            return m_text;
    }
    kak_assert(false);
    return {};
}

ColumnCount DisplayAtom::length() const
{
    switch (m_type)
    {
        case Range:
            return utf8::column_distance(get_iterator(*m_buffer, m_range.begin),
                                         get_iterator(*m_buffer, m_range.end));
        case Text:
        case ReplacedRange:
            return m_text.column_length();
    }
    kak_assert(false);
    return 0;
}

void DisplayAtom::trim_begin(ColumnCount count)
{
    if (m_type == Range)
        m_range.begin = utf8::advance(get_iterator(*m_buffer, m_range.begin),
                                      get_iterator(*m_buffer, m_range.end),
                                      count).coord();
    else
        m_text = m_text.substr(count).str();
}

void DisplayAtom::trim_end(ColumnCount count)
{
    if (m_type == Range)
        m_range.end = utf8::advance(get_iterator(*m_buffer, m_range.end),
                                    get_iterator(*m_buffer, m_range.begin),
                                    -count).coord();
    else
        m_text = m_text.substr(0, m_text.column_length() - count).str();
}

DisplayLine::DisplayLine(AtomList atoms)
    : m_atoms(std::move(atoms))
{
    compute_range();
}

DisplayLine::iterator DisplayLine::split(iterator it, BufferCoord pos)
{
    kak_assert(it->type() == DisplayAtom::Range);
    kak_assert(it->begin() < pos);
    kak_assert(it->end() > pos);

    DisplayAtom atom = *it;
    atom.m_range.end = pos;
    it->m_range.begin = pos;
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::split(iterator it, ColumnCount pos)
{
    kak_assert(it->type() == DisplayAtom::Text);
    kak_assert(pos > 0);
    kak_assert(pos < it->length());

    DisplayAtom atom(it->m_text.substr(0, pos).str());
    it->m_text = it->m_text.substr(pos).str();
    return m_atoms.insert(it, std::move(atom));
}

DisplayLine::iterator DisplayLine::insert(iterator it, DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    return m_atoms.insert(it, std::move(atom));
}

void DisplayLine::push_back(DisplayAtom atom)
{
    if (atom.has_buffer_range())
    {
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    m_atoms.push_back(std::move(atom));
}

DisplayLine::iterator DisplayLine::erase(iterator beg, iterator end)
{
    auto res = m_atoms.erase(beg, end);
    compute_range();
    return res;
}

void DisplayLine::optimize()
{
    if (m_atoms.empty())
        return;

    auto atom_it = m_atoms.begin();
    for (auto next_it = atom_it + 1; next_it != m_atoms.end(); ++next_it)
    {
        auto& atom = *atom_it;
        auto& next = *next_it;

        const auto type = atom.type();
        if (type == next.type() and atom.face == next.face)
        {
            if (type == DisplayAtom::Text)
                atom.m_text += next.m_text;
            else if ((type == DisplayAtom::Range or
                      type == DisplayAtom::ReplacedRange) and
                     next.begin() == atom.end())
            {
                atom.m_range.end = next.end();
                if (type == DisplayAtom::ReplacedRange)
                    atom.m_text += next.m_text;
            }
            else
                *++atom_it = std::move(*next_it);
        }
        else
            *++atom_it = std::move(*next_it);
    }
    m_atoms.erase(atom_it+1, m_atoms.end());
}

ColumnCount DisplayLine::length() const
{
    ColumnCount len = 0;
    for (auto& atom : m_atoms)
        len += atom.length();
    return len;
}

void DisplayLine::trim(ColumnCount first_col, ColumnCount col_count)
{
    for (auto it = begin(); first_col > 0 and it != end(); )
    {
        auto len = it->length();
        if (len <= first_col)
        {
            m_atoms.erase(it);
            first_col -= len;
        }
        else
        {
            it->trim_begin(first_col);
            first_col = 0;
        }
    }
    auto it = begin();
    for (; it != end() and col_count > 0; ++it)
        col_count -= it->length();

    if (col_count < 0)
        (it-1)->trim_end(-col_count);
    m_atoms.erase(it, end());

    compute_range();
}

const BufferRange init_range{ {INT_MAX, INT_MAX}, {INT_MIN, INT_MIN} };

void DisplayLine::compute_range()
{
    m_range = init_range;
    for (auto& atom : m_atoms)
    {
        if (not atom.has_buffer_range())
            continue;
        m_range.begin  = std::min(m_range.begin, atom.begin());
        m_range.end = std::max(m_range.end, atom.end());
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::compute_range()
{
    m_range = init_range;
    for (auto& line : m_lines)
    {
        m_range.begin  = std::min(line.range().begin, m_range.begin);
        m_range.end = std::max(line.range().end, m_range.end);
    }
    if (m_range == init_range)
        m_range = { { 0, 0 }, { 0, 0 } };
    kak_assert(m_range.begin <= m_range.end);
}

void DisplayBuffer::optimize()
{
    for (auto& line : m_lines)
        line.optimize();
}

DisplayLine parse_display_line(StringView line, const HashMap<String, DisplayLine>& builtins)
{
    DisplayLine res;
    bool was_antislash = false;
    auto pos = line.begin();
    String content;
    Face face;
    for (auto it = line.begin(), end = line.end(); it != end; ++it)
    {
        const char c = *it;
        if (c == '{')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                content.back() = '{';
                pos = it + 1;
            }
            else
            {
                content += StringView{pos, it};
                res.push_back({std::move(content), face});
                content.clear();
                auto closing = std::find(it+1, end, '}');
                if (closing == end)
                    throw runtime_error("unclosed face definition");
                if (*(it+1) == '{' and closing+1 != end and *(closing+1) == '}')
                {
                    auto builtin_it = builtins.find(StringView{it+2, closing});
                    if (builtin_it == builtins.end())
                        throw runtime_error(format("undefined atom {}", StringView{it+2, closing}));
                    for (auto& atom : builtin_it->value)
                        res.push_back(atom);
                    // closing is now at the first char of "}}", advance it to the second
                    ++closing;
                }
                else
                    face = get_face({it+1, closing});
                it = closing;
                pos = closing + 1;
            }
        }
        if (c == '\n') // line breaks are forbidden, replace with space
        {
            content += StringView{pos, it+1};
            content.back() = ' ';
            pos = it + 1;
        }

        if (c == '\\')
        {
            if (was_antislash)
            {
                content += StringView{pos, it};
                pos = it + 1;
                was_antislash = false;
            }
            else
                was_antislash = true;
        }
        else
            was_antislash = false;
    }
    content += StringView{pos, line.end()};
    if (not content.empty())
        res.push_back({std::move(content), face});
    return res;
}

}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2021                                                               *
 *                                                                                *
 * 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 <modules/base/basemodule.h>

#include <modules/base/dashboard/dashboarditemangle.h>
#include <modules/base/dashboard/dashboarditemdate.h>
#include <modules/base/dashboard/dashboarditemdistance.h>
#include <modules/base/dashboard/dashboarditemframerate.h>
#include <modules/base/dashboard/dashboarditemmission.h>
#include <modules/base/dashboard/dashboarditemparallelconnection.h>
#include <modules/base/dashboard/dashboarditempropertyvalue.h>
#include <modules/base/dashboard/dashboarditemsimulationincrement.h>
#include <modules/base/dashboard/dashboarditemspacing.h>
#include <modules/base/dashboard/dashboarditemtext.h>
#include <modules/base/dashboard/dashboarditemvelocity.h>
#include <modules/base/lightsource/cameralightsource.h>
#include <modules/base/lightsource/scenegraphlightsource.h>
#include <modules/base/rendering/grids/renderableboxgrid.h>
#include <modules/base/rendering/grids/renderablegrid.h>
#include <modules/base/rendering/grids/renderableradialgrid.h>
#include <modules/base/rendering/grids/renderablesphericalgrid.h>
#include <modules/base/rendering/renderablecartesianaxes.h>
#include <modules/base/rendering/renderabledisc.h>
#include <modules/base/rendering/renderablelabels.h>
#include <modules/base/rendering/renderablemodel.h>
#include <modules/base/rendering/renderablenodeline.h>
#include <modules/base/rendering/renderablesphere.h>
#include <modules/base/rendering/renderabletrailorbit.h>
#include <modules/base/rendering/renderabletrailtrajectory.h>
#include <modules/base/rendering/renderableplaneimagelocal.h>
#include <modules/base/rendering/renderableplaneimageonline.h>
#include <modules/base/rendering/modelgeometry.h>
#include <modules/base/rendering/multimodelgeometry.h>
#include <modules/base/rendering/screenspacedashboard.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include <modules/base/rendering/screenspaceimageonline.h>
#include <modules/base/rendering/screenspaceframebuffer.h>
#include <modules/base/rotation/constantrotation.h>
#include <modules/base/rotation/fixedrotation.h>
#include <modules/base/rotation/luarotation.h>
#include <modules/base/rotation/staticrotation.h>
#include <modules/base/rotation/timelinerotation.h>
#include <modules/base/scale/luascale.h>
#include <modules/base/scale/nonuniformstaticscale.h>
#include <modules/base/scale/staticscale.h>
#include <modules/base/scale/timedependentscale.h>
#include <modules/base/translation/timelinetranslation.h>
#include <modules/base/translation/luatranslation.h>
#include <modules/base/translation/statictranslation.h>
#include <modules/base/timeframe/timeframeinterval.h>
#include <modules/base/timeframe/timeframeunion.h>
#include <openspace/documentation/documentation.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/factorymanager.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/templatefactory.h>

namespace openspace {

ghoul::opengl::ProgramObjectManager BaseModule::ProgramObjectManager;
ghoul::opengl::TextureManager BaseModule::TextureManager;

BaseModule::BaseModule() : OpenSpaceModule(BaseModule::Name) {}

void BaseModule::internalInitialize(const ghoul::Dictionary&) {
    FactoryManager::ref().addFactory(
        std::make_unique<ghoul::TemplateFactory<modelgeometry::ModelGeometry>>(),
        "ModelGeometry"
    );
    FactoryManager::ref().addFactory(
        std::make_unique<ghoul::TemplateFactory<ScreenSpaceRenderable>>(),
        "ScreenSpaceRenderable"
    );

    auto fSsRenderable = FactoryManager::ref().factory<ScreenSpaceRenderable>();
    ghoul_assert(fSsRenderable, "ScreenSpaceRenderable factory was not created");

    fSsRenderable->registerClass<ScreenSpaceDashboard>("ScreenSpaceDashboard");
    fSsRenderable->registerClass<ScreenSpaceImageLocal>("ScreenSpaceImageLocal");
    fSsRenderable->registerClass<ScreenSpaceImageOnline>("ScreenSpaceImageOnline");
    fSsRenderable->registerClass<ScreenSpaceFramebuffer>("ScreenSpaceFramebuffer");

    auto fDashboard = FactoryManager::ref().factory<DashboardItem>();
    ghoul_assert(fDashboard, "Dashboard factory was not created");

    fDashboard->registerClass<DashboardItemAngle>("DashboardItemAngle");
    fDashboard->registerClass<DashboardItemDate>("DashboardItemDate");
    fDashboard->registerClass<DashboardItemDistance>("DashboardItemDistance");
    fDashboard->registerClass<DashboardItemFramerate>("DashboardItemFramerate");
    fDashboard->registerClass<DashboardItemMission>("DashboardItemMission");
    fDashboard->registerClass<DashboardItemParallelConnection>(
        "DashboardItemParallelConnection"
    );
    fDashboard->registerClass<DashboardItemPropertyValue>(
        "DashboardItemPropertyValue"
    );
    fDashboard->registerClass<DashboardItemSimulationIncrement>(
        "DashboardItemSimulationIncrement"
    );
    fDashboard->registerClass<DashboardItemSpacing>("DashboardItemSpacing");
    fDashboard->registerClass<DashboardItemText>("DashboardItemText");
    fDashboard->registerClass<DashboardItemVelocity>("DashboardItemVelocity");

    auto fRenderable = FactoryManager::ref().factory<Renderable>();
    ghoul_assert(fRenderable, "Renderable factory was not created");

    fRenderable->registerClass<RenderableBoxGrid>("RenderableBoxGrid");
    fRenderable->registerClass<RenderableCartesianAxes>("RenderableCartesianAxes");
    fRenderable->registerClass<RenderableDisc>("RenderableDisc");
    fRenderable->registerClass<RenderableGrid>("RenderableGrid");
    fRenderable->registerClass<RenderableLabels>("RenderableLabels");
    fRenderable->registerClass<RenderableModel>("RenderableModel");
    fRenderable->registerClass<RenderableNodeLine>("RenderableNodeLine");
    fRenderable->registerClass<RenderablePlaneImageLocal>("RenderablePlaneImageLocal");
    fRenderable->registerClass<RenderablePlaneImageOnline>("RenderablePlaneImageOnline");
    fRenderable->registerClass<RenderableRadialGrid>("RenderableRadialGrid");
    fRenderable->registerClass<RenderableSphere>("RenderableSphere");
    fRenderable->registerClass<RenderableSphericalGrid>("RenderableSphericalGrid");
    fRenderable->registerClass<RenderableTrailOrbit>("RenderableTrailOrbit");
    fRenderable->registerClass<RenderableTrailTrajectory>("RenderableTrailTrajectory");

    auto fTranslation = FactoryManager::ref().factory<Translation>();
    ghoul_assert(fTranslation, "Ephemeris factory was not created");

    fTranslation->registerClass<TimelineTranslation>("TimelineTranslation");
    fTranslation->registerClass<LuaTranslation>("LuaTranslation");
    fTranslation->registerClass<StaticTranslation>("StaticTranslation");

    auto fRotation = FactoryManager::ref().factory<Rotation>();
    ghoul_assert(fRotation, "Rotation factory was not created");

    fRotation->registerClass<ConstantRotation>("ConstantRotation");
    fRotation->registerClass<FixedRotation>("FixedRotation");
    fRotation->registerClass<LuaRotation>("LuaRotation");
    fRotation->registerClass<StaticRotation>("StaticRotation");
    fRotation->registerClass<TimelineRotation>("TimelineRotation");

    auto fScale = FactoryManager::ref().factory<Scale>();
    ghoul_assert(fScale, "Scale factory was not created");

    fScale->registerClass<LuaScale>("LuaScale");
    fScale->registerClass<NonUniformStaticScale>("NonUniformStaticScale");
    fScale->registerClass<StaticScale>("StaticScale");
    fScale->registerClass<TimeDependentScale>("TimeDependentScale");

    auto fTimeFrame = FactoryManager::ref().factory<TimeFrame>();
    ghoul_assert(fTimeFrame, "Scale factory was not created");

    fTimeFrame->registerClass<TimeFrameInterval>("TimeFrameInterval");
    fTimeFrame->registerClass<TimeFrameUnion>("TimeFrameUnion");

    auto fLightSource = FactoryManager::ref().factory<LightSource>();
    ghoul_assert(fLightSource, "Light Source factory was not created");

    fLightSource->registerClass<CameraLightSource>("CameraLightSource");
    fLightSource->registerClass<SceneGraphLightSource>("SceneGraphLightSource");

    auto fGeometry = FactoryManager::ref().factory<modelgeometry::ModelGeometry>();
    ghoul_assert(fGeometry, "Model geometry factory was not created");
    fGeometry->registerClass<modelgeometry::MultiModelGeometry>("MultiModelGeometry");
}

void BaseModule::internalDeinitializeGL() {
    ProgramObjectManager.releaseAll(ghoul::opengl::ProgramObjectManager::Warnings::Yes);
    TextureManager.releaseAll(ghoul::opengl::TextureManager::Warnings::Yes);
}

std::vector<documentation::Documentation> BaseModule::documentations() const {
    return {
        DashboardItemAngle::Documentation(),
        DashboardItemDate::Documentation(),
        DashboardItemDistance::Documentation(),
        DashboardItemFramerate::Documentation(),
        DashboardItemMission::Documentation(),
        DashboardItemSimulationIncrement::Documentation(),
        DashboardItemSpacing::Documentation(),
        DashboardItemVelocity::Documentation(),

        RenderableBoxGrid::Documentation(),
        RenderableGrid::Documentation(),
        RenderableLabels::Documentation(),
        RenderableModel::Documentation(),
        RenderableNodeLine::Documentation(),
        RenderablePlane::Documentation(),
        RenderableRadialGrid::Documentation(),
        RenderableDisc::Documentation(),
        RenderableSphere::Documentation(),
        RenderableSphericalGrid::Documentation(),
        RenderableTrailOrbit::Documentation(),
        RenderableTrailTrajectory::Documentation(),

        ScreenSpaceDashboard::Documentation(),
        ScreenSpaceFramebuffer::Documentation(),
        ScreenSpaceImageLocal::Documentation(),
        ScreenSpaceImageOnline::Documentation(),

        FixedRotation::Documentation(),
        LuaRotation::Documentation(),
        StaticRotation::Documentation(),
        TimelineRotation::Documentation(),

        LuaScale::Documentation(),
        StaticScale::Documentation(),
        TimeDependentScale::Documentation(),

        LuaTranslation::Documentation(),
        StaticTranslation::Documentation(),
        TimelineTranslation::Documentation(),

        TimeFrameInterval::Documentation(),
        TimeFrameUnion::Documentation(),

        SceneGraphLightSource::Documentation(),
        CameraLightSource::Documentation(),

        modelgeometry::ModelGeometry::Documentation(),
    };
}

std::vector<scripting::LuaLibrary> BaseModule::luaLibraries() const {
    return {
        ScreenSpaceDashboard::luaLibrary()
    };
}

} // namespace openspace
<commit_msg>Add missing documentation for NonUniformStaticScale<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2021                                                               *
 *                                                                                *
 * 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 <modules/base/basemodule.h>

#include <modules/base/dashboard/dashboarditemangle.h>
#include <modules/base/dashboard/dashboarditemdate.h>
#include <modules/base/dashboard/dashboarditemdistance.h>
#include <modules/base/dashboard/dashboarditemframerate.h>
#include <modules/base/dashboard/dashboarditemmission.h>
#include <modules/base/dashboard/dashboarditemparallelconnection.h>
#include <modules/base/dashboard/dashboarditempropertyvalue.h>
#include <modules/base/dashboard/dashboarditemsimulationincrement.h>
#include <modules/base/dashboard/dashboarditemspacing.h>
#include <modules/base/dashboard/dashboarditemtext.h>
#include <modules/base/dashboard/dashboarditemvelocity.h>
#include <modules/base/lightsource/cameralightsource.h>
#include <modules/base/lightsource/scenegraphlightsource.h>
#include <modules/base/rendering/grids/renderableboxgrid.h>
#include <modules/base/rendering/grids/renderablegrid.h>
#include <modules/base/rendering/grids/renderableradialgrid.h>
#include <modules/base/rendering/grids/renderablesphericalgrid.h>
#include <modules/base/rendering/renderablecartesianaxes.h>
#include <modules/base/rendering/renderabledisc.h>
#include <modules/base/rendering/renderablelabels.h>
#include <modules/base/rendering/renderablemodel.h>
#include <modules/base/rendering/renderablenodeline.h>
#include <modules/base/rendering/renderablesphere.h>
#include <modules/base/rendering/renderabletrailorbit.h>
#include <modules/base/rendering/renderabletrailtrajectory.h>
#include <modules/base/rendering/renderableplaneimagelocal.h>
#include <modules/base/rendering/renderableplaneimageonline.h>
#include <modules/base/rendering/modelgeometry.h>
#include <modules/base/rendering/multimodelgeometry.h>
#include <modules/base/rendering/screenspacedashboard.h>
#include <modules/base/rendering/screenspaceimagelocal.h>
#include <modules/base/rendering/screenspaceimageonline.h>
#include <modules/base/rendering/screenspaceframebuffer.h>
#include <modules/base/rotation/constantrotation.h>
#include <modules/base/rotation/fixedrotation.h>
#include <modules/base/rotation/luarotation.h>
#include <modules/base/rotation/staticrotation.h>
#include <modules/base/rotation/timelinerotation.h>
#include <modules/base/scale/luascale.h>
#include <modules/base/scale/nonuniformstaticscale.h>
#include <modules/base/scale/staticscale.h>
#include <modules/base/scale/timedependentscale.h>
#include <modules/base/translation/timelinetranslation.h>
#include <modules/base/translation/luatranslation.h>
#include <modules/base/translation/statictranslation.h>
#include <modules/base/timeframe/timeframeinterval.h>
#include <modules/base/timeframe/timeframeunion.h>
#include <openspace/documentation/documentation.h>
#include <openspace/rendering/renderable.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/util/factorymanager.h>
#include <ghoul/misc/assert.h>
#include <ghoul/misc/templatefactory.h>

namespace openspace {

ghoul::opengl::ProgramObjectManager BaseModule::ProgramObjectManager;
ghoul::opengl::TextureManager BaseModule::TextureManager;

BaseModule::BaseModule() : OpenSpaceModule(BaseModule::Name) {}

void BaseModule::internalInitialize(const ghoul::Dictionary&) {
    FactoryManager::ref().addFactory(
        std::make_unique<ghoul::TemplateFactory<modelgeometry::ModelGeometry>>(),
        "ModelGeometry"
    );
    FactoryManager::ref().addFactory(
        std::make_unique<ghoul::TemplateFactory<ScreenSpaceRenderable>>(),
        "ScreenSpaceRenderable"
    );

    auto fSsRenderable = FactoryManager::ref().factory<ScreenSpaceRenderable>();
    ghoul_assert(fSsRenderable, "ScreenSpaceRenderable factory was not created");

    fSsRenderable->registerClass<ScreenSpaceDashboard>("ScreenSpaceDashboard");
    fSsRenderable->registerClass<ScreenSpaceImageLocal>("ScreenSpaceImageLocal");
    fSsRenderable->registerClass<ScreenSpaceImageOnline>("ScreenSpaceImageOnline");
    fSsRenderable->registerClass<ScreenSpaceFramebuffer>("ScreenSpaceFramebuffer");

    auto fDashboard = FactoryManager::ref().factory<DashboardItem>();
    ghoul_assert(fDashboard, "Dashboard factory was not created");

    fDashboard->registerClass<DashboardItemAngle>("DashboardItemAngle");
    fDashboard->registerClass<DashboardItemDate>("DashboardItemDate");
    fDashboard->registerClass<DashboardItemDistance>("DashboardItemDistance");
    fDashboard->registerClass<DashboardItemFramerate>("DashboardItemFramerate");
    fDashboard->registerClass<DashboardItemMission>("DashboardItemMission");
    fDashboard->registerClass<DashboardItemParallelConnection>(
        "DashboardItemParallelConnection"
    );
    fDashboard->registerClass<DashboardItemPropertyValue>(
        "DashboardItemPropertyValue"
    );
    fDashboard->registerClass<DashboardItemSimulationIncrement>(
        "DashboardItemSimulationIncrement"
    );
    fDashboard->registerClass<DashboardItemSpacing>("DashboardItemSpacing");
    fDashboard->registerClass<DashboardItemText>("DashboardItemText");
    fDashboard->registerClass<DashboardItemVelocity>("DashboardItemVelocity");

    auto fRenderable = FactoryManager::ref().factory<Renderable>();
    ghoul_assert(fRenderable, "Renderable factory was not created");

    fRenderable->registerClass<RenderableBoxGrid>("RenderableBoxGrid");
    fRenderable->registerClass<RenderableCartesianAxes>("RenderableCartesianAxes");
    fRenderable->registerClass<RenderableDisc>("RenderableDisc");
    fRenderable->registerClass<RenderableGrid>("RenderableGrid");
    fRenderable->registerClass<RenderableLabels>("RenderableLabels");
    fRenderable->registerClass<RenderableModel>("RenderableModel");
    fRenderable->registerClass<RenderableNodeLine>("RenderableNodeLine");
    fRenderable->registerClass<RenderablePlaneImageLocal>("RenderablePlaneImageLocal");
    fRenderable->registerClass<RenderablePlaneImageOnline>("RenderablePlaneImageOnline");
    fRenderable->registerClass<RenderableRadialGrid>("RenderableRadialGrid");
    fRenderable->registerClass<RenderableSphere>("RenderableSphere");
    fRenderable->registerClass<RenderableSphericalGrid>("RenderableSphericalGrid");
    fRenderable->registerClass<RenderableTrailOrbit>("RenderableTrailOrbit");
    fRenderable->registerClass<RenderableTrailTrajectory>("RenderableTrailTrajectory");

    auto fTranslation = FactoryManager::ref().factory<Translation>();
    ghoul_assert(fTranslation, "Ephemeris factory was not created");

    fTranslation->registerClass<TimelineTranslation>("TimelineTranslation");
    fTranslation->registerClass<LuaTranslation>("LuaTranslation");
    fTranslation->registerClass<StaticTranslation>("StaticTranslation");

    auto fRotation = FactoryManager::ref().factory<Rotation>();
    ghoul_assert(fRotation, "Rotation factory was not created");

    fRotation->registerClass<ConstantRotation>("ConstantRotation");
    fRotation->registerClass<FixedRotation>("FixedRotation");
    fRotation->registerClass<LuaRotation>("LuaRotation");
    fRotation->registerClass<StaticRotation>("StaticRotation");
    fRotation->registerClass<TimelineRotation>("TimelineRotation");

    auto fScale = FactoryManager::ref().factory<Scale>();
    ghoul_assert(fScale, "Scale factory was not created");

    fScale->registerClass<LuaScale>("LuaScale");
    fScale->registerClass<NonUniformStaticScale>("NonUniformStaticScale");
    fScale->registerClass<StaticScale>("StaticScale");
    fScale->registerClass<TimeDependentScale>("TimeDependentScale");

    auto fTimeFrame = FactoryManager::ref().factory<TimeFrame>();
    ghoul_assert(fTimeFrame, "Scale factory was not created");

    fTimeFrame->registerClass<TimeFrameInterval>("TimeFrameInterval");
    fTimeFrame->registerClass<TimeFrameUnion>("TimeFrameUnion");

    auto fLightSource = FactoryManager::ref().factory<LightSource>();
    ghoul_assert(fLightSource, "Light Source factory was not created");

    fLightSource->registerClass<CameraLightSource>("CameraLightSource");
    fLightSource->registerClass<SceneGraphLightSource>("SceneGraphLightSource");

    auto fGeometry = FactoryManager::ref().factory<modelgeometry::ModelGeometry>();
    ghoul_assert(fGeometry, "Model geometry factory was not created");
    fGeometry->registerClass<modelgeometry::MultiModelGeometry>("MultiModelGeometry");
}

void BaseModule::internalDeinitializeGL() {
    ProgramObjectManager.releaseAll(ghoul::opengl::ProgramObjectManager::Warnings::Yes);
    TextureManager.releaseAll(ghoul::opengl::TextureManager::Warnings::Yes);
}

std::vector<documentation::Documentation> BaseModule::documentations() const {
    return {
        DashboardItemAngle::Documentation(),
        DashboardItemDate::Documentation(),
        DashboardItemDistance::Documentation(),
        DashboardItemFramerate::Documentation(),
        DashboardItemMission::Documentation(),
        DashboardItemSimulationIncrement::Documentation(),
        DashboardItemSpacing::Documentation(),
        DashboardItemVelocity::Documentation(),

        RenderableBoxGrid::Documentation(),
        RenderableGrid::Documentation(),
        RenderableLabels::Documentation(),
        RenderableModel::Documentation(),
        RenderableNodeLine::Documentation(),
        RenderablePlane::Documentation(),
        RenderableRadialGrid::Documentation(),
        RenderableDisc::Documentation(),
        RenderableSphere::Documentation(),
        RenderableSphericalGrid::Documentation(),
        RenderableTrailOrbit::Documentation(),
        RenderableTrailTrajectory::Documentation(),

        ScreenSpaceDashboard::Documentation(),
        ScreenSpaceFramebuffer::Documentation(),
        ScreenSpaceImageLocal::Documentation(),
        ScreenSpaceImageOnline::Documentation(),

        FixedRotation::Documentation(),
        LuaRotation::Documentation(),
        StaticRotation::Documentation(),
        TimelineRotation::Documentation(),

        LuaScale::Documentation(),
        NonUniformStaticScale::Documentation(),
        StaticScale::Documentation(),
        TimeDependentScale::Documentation(),

        LuaTranslation::Documentation(),
        StaticTranslation::Documentation(),
        TimelineTranslation::Documentation(),

        TimeFrameInterval::Documentation(),
        TimeFrameUnion::Documentation(),

        SceneGraphLightSource::Documentation(),
        CameraLightSource::Documentation(),

        modelgeometry::ModelGeometry::Documentation(),
    };
}

std::vector<scripting::LuaLibrary> BaseModule::luaLibraries() const {
    return {
        ScreenSpaceDashboard::luaLibrary()
    };
}

} // namespace openspace
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include <algorithm>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/regex.hpp>
#include <cstring>
#include <fstream>
#include <gtest/gtest.h>
#include <sstream>

#include "ControlFlow.h"
#include "Debug.h"
#include "DexInstruction.h"
#include "IRCode.h"
#include "Show.h"
#include "VerifyUtil.h"
#include "Walkers.h"

DexClass* find_class_named(const DexClasses& classes, const char* name) {
  auto it =
      std::find_if(classes.begin(), classes.end(), [&name](DexClass* cls) {
        return !strcmp(name, cls->get_name()->c_str());
      });
  return it == classes.end() ? nullptr : *it;
}

DexField* find_ifield_named(const DexClass& cls, const char* name) {
  auto fields = cls.get_ifields();
  auto it =
      std::find_if(fields.begin(), fields.end(), [&name](const DexField* f) {
        return strcmp(name, f->get_name()->c_str()) == 0;
      });
  return it == fields.end() ? nullptr : *it;
}

DexField* find_sfield_named(const DexClass& cls, const char* name) {
  auto fields = cls.get_sfields();
  auto it =
      std::find_if(fields.begin(), fields.end(), [&name](const DexField* f) {
        return strcmp(name, f->get_name()->c_str()) == 0;
      });
  return it == fields.end() ? nullptr : *it;
}

DexField* find_field_named(const DexClass& cls, const char* name) {
  auto ret = find_ifield_named(cls, name);
  if (ret) {
    return ret;
  }
  return find_sfield_named(cls, name);
}

DexMethod* find_vmethod_named(const DexClass& cls, const char* name) {
  auto vmethods = cls.get_vmethods();
  auto it =
      std::find_if(vmethods.begin(), vmethods.end(), [&name](DexMethod* m) {
        return strcmp(name, m->get_name()->c_str()) == 0;
      });
  return it == vmethods.end() ? nullptr : *it;
}

DexMethod* find_dmethod_named(const DexClass& cls, const char* name) {
  auto dmethods = cls.get_dmethods();
  auto it =
      std::find_if(dmethods.begin(), dmethods.end(), [&name](DexMethod* m) {
        return strcmp(name, m->get_name()->c_str()) == 0;
      });
  return it == dmethods.end() ? nullptr : *it;
}

DexMethod* find_method_named(const DexClass& cls, const char* name) {
  auto ret = find_dmethod_named(cls, name);
  if (ret != nullptr) {
    return ret;
  }
  return find_vmethod_named(cls, name);
}

DexOpcodeMethod* find_invoke(const DexMethod* m,
                             DexOpcode opcode,
                             const char* target_mname,
                             DexType* receiver) {
  auto insns = m->get_dex_code()->get_instructions();
  return find_invoke(
      insns.begin(), insns.end(), opcode, target_mname, receiver);
}

DexOpcodeMethod* find_invoke(std::vector<DexInstruction*>::iterator begin,
                             std::vector<DexInstruction*>::iterator end,
                             DexOpcode opcode,
                             const char* target_mname,
                             DexType* receiver) {
  auto it = std::find_if(
      begin, end, [opcode, target_mname, receiver](DexInstruction* insn) {
        if (insn->opcode() != opcode) {
          return false;
        }
        auto meth = static_cast<DexOpcodeMethod*>(insn)->get_method();
        if (receiver && meth->get_class() != receiver) {
          return false;
        }
        auto mname =
            static_cast<DexOpcodeMethod*>(insn)->get_method()->get_name();
        return mname == DexString::get_string(target_mname);
      });
  return it == end ? nullptr : static_cast<DexOpcodeMethod*>(*it);
}

// Given a semicolon delimited list of extracted files from the APK, return a
// map of the original APK's file path to its path on disk.
ResourceFiles decode_resource_paths(const char* location, const char* suffix) {
  ResourceFiles files;
  std::istringstream input;
  input.str(location);
  for (std::string file_path; std::getline(input, file_path, ':');) {
    auto pos = file_path.rfind('/');
    always_assert(pos >= 0 && pos + 1 < file_path.length());
    auto directory = file_path.substr(0, pos);
    if (boost::algorithm::ends_with(directory, suffix)) {
      auto original_name = file_path.substr(pos + 1);
      // Undo simple escaping at buck_imports/redex_utils
      boost::replace_all(original_name, "zC", ":");
      boost::replace_all(original_name, "zS", "/");
      boost::replace_all(original_name, "zZ", "z");
      files.emplace(original_name, file_path);
    }
  }
  return files;
}

DexInstruction* find_instruction(DexMethod* m, DexOpcode opcode) {
  auto& insns = m->get_dex_code()->get_instructions();
  auto it =
      std::find_if(insns.begin(), insns.end(), [opcode](DexInstruction* insn) {
        return insn->opcode() == opcode;
      });
  return it == insns.end() ? nullptr : *it;
}

void verify_type_erased(const DexClass* cls, size_t num_dmethods) {
  if (!cls) {
    ASSERT_EQ(num_dmethods, 0)
        << "cls is null, can not have " << num_dmethods << " dmethods\n";
    return;
  }
  ASSERT_EQ(cls->get_interfaces()->size(), 0)
      << "cls " << show(cls) << " has interfaces "
      << show(cls->get_interfaces()) << "\n";
  ASSERT_EQ(cls->get_super_class(), type::java_lang_Object())
      << "cls " << show(cls) << " has super_cls "
      << show(cls->get_super_class()) << "\n";
  auto dmethods = cls->get_dmethods();
  ASSERT_EQ(dmethods.size(), num_dmethods)
      << show(cls) << " has " << dmethods.size() << " dmethods\n";
  for (auto m : dmethods) {
    ASSERT_FALSE(method::is_init(m));
    ASSERT_NE(m->c_str(), "<init>");
  }
  const auto& vmethods = cls->get_vmethods();
  ASSERT_TRUE(vmethods.empty())
      << show(cls) << " has " << vmethods.size() << " vmethods\n";
}

void dump_cfgs(bool is_prev_verify,
               const DexClass* cls,
               const std::function<bool(const DexMethod*)>& filter) {
  using namespace cfg;
  const char* base_filename =
      std::getenv("REDEX_INSTRUMENT_TEST_BASE_FILENAME");
  if (base_filename == nullptr) {
    return;
  }

  std::ofstream file((is_prev_verify ? "before_" : "after_") +
                     std::string(base_filename));
  boost::regex addr("\\[0x[0-9a-f]+\\] ");
  walk::methods(std::vector<const DexClass*>{cls}, [&](DexMethod* method) {
    if (!filter(method)) {
      return;
    }

    file << "============================================================\n";
    file << (is_prev_verify ? "Before: " : "After: ") << show(method) << '\n';
    file << "============================================================\n";

    method->balloon();
    IRCode* code = method->get_code();
    code->build_cfg(/*editable*/ false);
    cfg::ControlFlowGraph& cfg = code->cfg();
    cfg.write_dot_format(file);

    // Dump CFG wihout address parts for easier diff between before/after files.
    std::stringstream ss;
    ss << show(cfg) << "\n\n";
    file << boost::regex_replace(ss.str(), addr, "");
  });
}
<commit_msg>Use default ASAN options in instr verify code<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include <algorithm>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/regex.hpp>
#include <cstring>
#include <fstream>
#include <gtest/gtest.h>
#include <sstream>

#include "ControlFlow.h"
#include "Debug.h"
#include "DexInstruction.h"
#include "IRCode.h"
#include "SanitizersConfig.h"
#include "Show.h"
#include "VerifyUtil.h"
#include "Walkers.h"

DexClass* find_class_named(const DexClasses& classes, const char* name) {
  auto it =
      std::find_if(classes.begin(), classes.end(), [&name](DexClass* cls) {
        return !strcmp(name, cls->get_name()->c_str());
      });
  return it == classes.end() ? nullptr : *it;
}

DexField* find_ifield_named(const DexClass& cls, const char* name) {
  auto fields = cls.get_ifields();
  auto it =
      std::find_if(fields.begin(), fields.end(), [&name](const DexField* f) {
        return strcmp(name, f->get_name()->c_str()) == 0;
      });
  return it == fields.end() ? nullptr : *it;
}

DexField* find_sfield_named(const DexClass& cls, const char* name) {
  auto fields = cls.get_sfields();
  auto it =
      std::find_if(fields.begin(), fields.end(), [&name](const DexField* f) {
        return strcmp(name, f->get_name()->c_str()) == 0;
      });
  return it == fields.end() ? nullptr : *it;
}

DexField* find_field_named(const DexClass& cls, const char* name) {
  auto ret = find_ifield_named(cls, name);
  if (ret) {
    return ret;
  }
  return find_sfield_named(cls, name);
}

DexMethod* find_vmethod_named(const DexClass& cls, const char* name) {
  auto vmethods = cls.get_vmethods();
  auto it =
      std::find_if(vmethods.begin(), vmethods.end(), [&name](DexMethod* m) {
        return strcmp(name, m->get_name()->c_str()) == 0;
      });
  return it == vmethods.end() ? nullptr : *it;
}

DexMethod* find_dmethod_named(const DexClass& cls, const char* name) {
  auto dmethods = cls.get_dmethods();
  auto it =
      std::find_if(dmethods.begin(), dmethods.end(), [&name](DexMethod* m) {
        return strcmp(name, m->get_name()->c_str()) == 0;
      });
  return it == dmethods.end() ? nullptr : *it;
}

DexMethod* find_method_named(const DexClass& cls, const char* name) {
  auto ret = find_dmethod_named(cls, name);
  if (ret != nullptr) {
    return ret;
  }
  return find_vmethod_named(cls, name);
}

DexOpcodeMethod* find_invoke(const DexMethod* m,
                             DexOpcode opcode,
                             const char* target_mname,
                             DexType* receiver) {
  auto insns = m->get_dex_code()->get_instructions();
  return find_invoke(
      insns.begin(), insns.end(), opcode, target_mname, receiver);
}

DexOpcodeMethod* find_invoke(std::vector<DexInstruction*>::iterator begin,
                             std::vector<DexInstruction*>::iterator end,
                             DexOpcode opcode,
                             const char* target_mname,
                             DexType* receiver) {
  auto it = std::find_if(
      begin, end, [opcode, target_mname, receiver](DexInstruction* insn) {
        if (insn->opcode() != opcode) {
          return false;
        }
        auto meth = static_cast<DexOpcodeMethod*>(insn)->get_method();
        if (receiver && meth->get_class() != receiver) {
          return false;
        }
        auto mname =
            static_cast<DexOpcodeMethod*>(insn)->get_method()->get_name();
        return mname == DexString::get_string(target_mname);
      });
  return it == end ? nullptr : static_cast<DexOpcodeMethod*>(*it);
}

// Given a semicolon delimited list of extracted files from the APK, return a
// map of the original APK's file path to its path on disk.
ResourceFiles decode_resource_paths(const char* location, const char* suffix) {
  ResourceFiles files;
  std::istringstream input;
  input.str(location);
  for (std::string file_path; std::getline(input, file_path, ':');) {
    auto pos = file_path.rfind('/');
    always_assert(pos >= 0 && pos + 1 < file_path.length());
    auto directory = file_path.substr(0, pos);
    if (boost::algorithm::ends_with(directory, suffix)) {
      auto original_name = file_path.substr(pos + 1);
      // Undo simple escaping at buck_imports/redex_utils
      boost::replace_all(original_name, "zC", ":");
      boost::replace_all(original_name, "zS", "/");
      boost::replace_all(original_name, "zZ", "z");
      files.emplace(original_name, file_path);
    }
  }
  return files;
}

DexInstruction* find_instruction(DexMethod* m, DexOpcode opcode) {
  auto& insns = m->get_dex_code()->get_instructions();
  auto it =
      std::find_if(insns.begin(), insns.end(), [opcode](DexInstruction* insn) {
        return insn->opcode() == opcode;
      });
  return it == insns.end() ? nullptr : *it;
}

void verify_type_erased(const DexClass* cls, size_t num_dmethods) {
  if (!cls) {
    ASSERT_EQ(num_dmethods, 0)
        << "cls is null, can not have " << num_dmethods << " dmethods\n";
    return;
  }
  ASSERT_EQ(cls->get_interfaces()->size(), 0)
      << "cls " << show(cls) << " has interfaces "
      << show(cls->get_interfaces()) << "\n";
  ASSERT_EQ(cls->get_super_class(), type::java_lang_Object())
      << "cls " << show(cls) << " has super_cls "
      << show(cls->get_super_class()) << "\n";
  auto dmethods = cls->get_dmethods();
  ASSERT_EQ(dmethods.size(), num_dmethods)
      << show(cls) << " has " << dmethods.size() << " dmethods\n";
  for (auto m : dmethods) {
    ASSERT_FALSE(method::is_init(m));
    ASSERT_NE(m->c_str(), "<init>");
  }
  const auto& vmethods = cls->get_vmethods();
  ASSERT_TRUE(vmethods.empty())
      << show(cls) << " has " << vmethods.size() << " vmethods\n";
}

void dump_cfgs(bool is_prev_verify,
               const DexClass* cls,
               const std::function<bool(const DexMethod*)>& filter) {
  using namespace cfg;
  const char* base_filename =
      std::getenv("REDEX_INSTRUMENT_TEST_BASE_FILENAME");
  if (base_filename == nullptr) {
    return;
  }

  std::ofstream file((is_prev_verify ? "before_" : "after_") +
                     std::string(base_filename));
  boost::regex addr("\\[0x[0-9a-f]+\\] ");
  walk::methods(std::vector<const DexClass*>{cls}, [&](DexMethod* method) {
    if (!filter(method)) {
      return;
    }

    file << "============================================================\n";
    file << (is_prev_verify ? "Before: " : "After: ") << show(method) << '\n';
    file << "============================================================\n";

    method->balloon();
    IRCode* code = method->get_code();
    code->build_cfg(/*editable*/ false);
    cfg::ControlFlowGraph& cfg = code->cfg();
    cfg.write_dot_format(file);

    // Dump CFG wihout address parts for easier diff between before/after files.
    std::stringstream ss;
    ss << show(cfg) << "\n\n";
    file << boost::regex_replace(ss.str(), addr, "");
  });
}
<|endoftext|>


<commit_before>// set of classes to compare the performance of STL vector versus
// native Root TClonesArray.
// See main program bench.cxx

#include "TRandom.h"
#include "TFile.h"
#include "TTree.h"
#include "TClass.h"
//the next include must be the last one on systems like Windows/NT
#include "TBench.h"

THit hit;
const char *demofile = "$TEMP/bench.root";

//-------------------------------------------------------------
ClassImp(THit)
//-------------------------------------------------------------
THit::THit() {
  fPulses = 0;
}
THit::THit(const THit &hit) {
  fX = hit.fX;
  fY = hit.fY;
  fZ = hit.fZ;
  for (Int_t i=0;i<10;i++) fTime[i] = hit.fTime[i];
  fPulses = 0;
  fNpulses = hit.fNpulses;
  if (fNpulses == 0) return;
  if (hit.fPulses == 0) return;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = hit.fPulses[j];
}

THit::THit(int t) {
  fPulses = 0;
  Set(t);
}

THit::~THit() {
   if (fPulses) delete [] fPulses;
   fPulses = 0;
}

void THit::Set(int t) {
  fX = gRandom->Gaus(0,1);
  fY = gRandom->Gaus(0,1);
  fZ = gRandom->Gaus(0,10);
  if (fPulses && fNpulses > 0) delete [] fPulses;
  fNpulses = t%20 + 1;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = j+1;
  for (int i=0; i<10; i++) fTime[i] = t+i;
}

#if 0
#if defined(R__TEMPLATE_OVERLOAD_BUG)
template <>
#endif
TBuffer &operator>>(TBuffer &buf, THit *&obj)
{
   obj = new THit();
   obj->Streamer(buf);
   return buf;
}
#endif

TBuffer &operator<<(TBuffer &buf, const THit *obj)
{
   ((THit*)obj)->Streamer(buf);
   return buf;
}

//-------------------------------------------------------------
ClassImp(TObjHit)
//-------------------------------------------------------------

TObjHit::TObjHit() :THit() {}
TObjHit::TObjHit(int t) :THit(t) {}

//-------------------------------------------------------------
ClassImp(TSTLhit)
//-------------------------------------------------------------
TSTLhit::TSTLhit()
{
}

TSTLhit::TSTLhit(Int_t nmax)
{
   fNhits = nmax;
   fList1.reserve(nmax);
}

TSTLhit::~TSTLhit() {
}

void TSTLhit::Clear(Option_t *)
{
   fList1.erase(fList1.begin(),fList1.end());
}

void TSTLhit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      hit.Set(j);
      fList1.push_back(hit);
   }
}

Int_t TSTLhit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhit::ReadTree()
{
  TSTLhit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TSTLhitStar)
//-------------------------------------------------------------
TSTLhitStar::TSTLhitStar()
{
}

TSTLhitStar::TSTLhitStar(Int_t nmax)
{
   fNhits = nmax;
   fList2.reserve(nmax);
}

TSTLhitStar::~TSTLhitStar() {
}

void TSTLhitStar::Clear(Option_t *)
{
   for (vector<THit*>::iterator it = fList2.begin(); it<fList2.end(); it++) {
      delete (*it);
   }
   fList2.erase(fList2.begin(),fList2.end());
}

void TSTLhitStar::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      fList2.push_back(new THit(j));
   }
}

Int_t TSTLhitStar::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhitStar *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhitStar",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhitStar",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhitStar::ReadTree()
{
  TSTLhitStar *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TCloneshit)
//-------------------------------------------------------------
TCloneshit::TCloneshit()
{
   fList3 = new TClonesArray("TObjHit");
}

TCloneshit::TCloneshit(Int_t nmax)
{
   fNhits = nmax;
   fList3 = new TClonesArray("TObjHit",nmax);
   TObjHit::Class()->IgnoreTObjectStreamer();
}

TCloneshit::~TCloneshit() {
}

void TCloneshit::Clear(Option_t *)
{
   fList3->Delete();
   //fList3->Clear();
}

void TCloneshit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      new((*fList3)[j]) TObjHit(j);
   }
}

Int_t TCloneshit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TCloneshit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","Cloneshit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TCloneshit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TCloneshit::ReadTree()
{
  TCloneshit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
  }
  delete f;
  return nbytes;
}

<commit_msg>Undo Philippe's change in TBench. Use /tmp/bench.root instead of $TEMP.<commit_after>// set of classes to compare the performance of STL vector versus
// native Root TClonesArray.
// See main program bench.cxx

#include "TRandom.h"
#include "TFile.h"
#include "TTree.h"
#include "TClass.h"
//the next include must be the last one on systems like Windows/NT
#include "TBench.h"

THit hit;
const char *demofile = "/tmp/bench.root";

//-------------------------------------------------------------
ClassImp(THit)
//-------------------------------------------------------------
THit::THit() {
  fPulses = 0;
}
THit::THit(const THit &hit) {
  fX = hit.fX;
  fY = hit.fY;
  fZ = hit.fZ;
  for (Int_t i=0;i<10;i++) fTime[i] = hit.fTime[i];
  fPulses = 0;
  fNpulses = hit.fNpulses;
  if (fNpulses == 0) return;
  if (hit.fPulses == 0) return;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = hit.fPulses[j];
}

THit::THit(int t) {
  fPulses = 0;
  Set(t);
}

THit::~THit() {
   if (fPulses) delete [] fPulses;
   fPulses = 0;
}

void THit::Set(int t) {
  fX = gRandom->Gaus(0,1);
  fY = gRandom->Gaus(0,1);
  fZ = gRandom->Gaus(0,10);
  if (fPulses && fNpulses > 0) delete [] fPulses;
  fNpulses = t%20 + 1;
  fPulses = new int[fNpulses];
  for (int j=0;j<fNpulses;j++) fPulses[j] = j+1;
  for (int i=0; i<10; i++) fTime[i] = t+i;
}

#if 0
#if defined(R__TEMPLATE_OVERLOAD_BUG)
template <>
#endif
TBuffer &operator>>(TBuffer &buf, THit *&obj)
{
   obj = new THit();
   obj->Streamer(buf);
   return buf;
}
#endif

TBuffer &operator<<(TBuffer &buf, const THit *obj)
{
   ((THit*)obj)->Streamer(buf);
   return buf;
}

//-------------------------------------------------------------
ClassImp(TObjHit)
//-------------------------------------------------------------

TObjHit::TObjHit() :THit() {}
TObjHit::TObjHit(int t) :THit(t) {}

//-------------------------------------------------------------
ClassImp(TSTLhit)
//-------------------------------------------------------------
TSTLhit::TSTLhit()
{
}

TSTLhit::TSTLhit(Int_t nmax)
{
   fNhits = nmax;
   fList1.reserve(nmax);
}

TSTLhit::~TSTLhit() {
}

void TSTLhit::Clear(Option_t *)
{
   fList1.erase(fList1.begin(),fList1.end());
}

void TSTLhit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      hit.Set(j);
      fList1.push_back(hit);
   }
}

Int_t TSTLhit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhit::ReadTree()
{
  TSTLhit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TSTLhitStar)
//-------------------------------------------------------------
TSTLhitStar::TSTLhitStar()
{
}

TSTLhitStar::TSTLhitStar(Int_t nmax)
{
   fNhits = nmax;
   fList2.reserve(nmax);
}

TSTLhitStar::~TSTLhitStar() {
}

void TSTLhitStar::Clear(Option_t *)
{
   for (vector<THit*>::iterator it = fList2.begin(); it<fList2.end(); it++) {
      delete (*it);
   }
   fList2.erase(fList2.begin(),fList2.end());
}

void TSTLhitStar::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      fList2.push_back(new THit(j));
   }
}

Int_t TSTLhitStar::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TSTLhitStar *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","STLhitStar",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TSTLhitStar",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TSTLhitStar::ReadTree()
{
  TSTLhitStar *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
     Clear();
  }
  delete f;
  return nbytes;
}

//-------------------------------------------------------------
ClassImp(TCloneshit)
//-------------------------------------------------------------
TCloneshit::TCloneshit()
{
   fList3 = new TClonesArray("TObjHit");
}

TCloneshit::TCloneshit(Int_t nmax)
{
   fNhits = nmax;
   fList3 = new TClonesArray("TObjHit",nmax);
   TObjHit::Class()->IgnoreTObjectStreamer();
}

TCloneshit::~TCloneshit() {
}

void TCloneshit::Clear(Option_t *)
{
   fList3->Delete();
   //fList3->Clear();
}

void TCloneshit::MakeEvent(int ievent)
{
   Clear();
   for (Int_t j=0; j<fNhits; j++) {
      new((*fList3)[j]) TObjHit(j);
   }
}

Int_t TCloneshit::MakeTree(int mode, int nevents, int compression, int split, float &cx)
{
  TFile *f=0;
  TTree *T=0;
  TCloneshit *top = this;
  if (mode > 0) {
     f = new TFile(demofile,"recreate","Cloneshit",compression);
     T = new TTree("T","Demo tree");
     T->Branch("event","TCloneshit",&top,64000,split);
  }
  for (int ievent=0; ievent<nevents; ievent++) {
     MakeEvent(ievent);
     if (mode > 0) T->Fill();
  }

  if (mode == 0) return 0;
  T->Write();
  delete f;
  f = new TFile(demofile);
  Int_t nbytes = f->GetEND();
  cx = f->GetCompressionFactor();
  delete f;
  return nbytes;
}

Int_t TCloneshit::ReadTree()
{
  TCloneshit *top = this;
  TFile *f = new TFile(demofile);
  TTree *T = (TTree*)f->Get("T");
  T->SetBranchAddress("event",&top);
  Int_t nevents = (Int_t)T->GetEntries();
  Int_t nbytes = 0;
  for (int ievent=0; ievent<nevents; ievent++) {
     nbytes += T->GetEntry(ievent);
  }
  delete f;
  return nbytes;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "test/lib/sstable_utils.hh"

#include "database.hh"
#include "memtable-sstable.hh"
#include "dht/i_partitioner.hh"
#include "dht/murmur3_partitioner.hh"
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/sort.hpp>
#include "sstables/version.hh"
#include "test/lib/flat_mutation_reader_assertions.hh"
#include "test/lib/reader_concurrency_semaphore.hh"
#include <seastar/core/reactor.hh>
#include <seastar/core/seastar.hh>
#include <seastar/core/coroutine.hh>

using namespace sstables;
using namespace std::chrono_literals;

std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size, std::optional<shard_id> shard) {
    std::vector<std::pair<sstring, dht::decorated_key>> p;
    p.reserve(n);

    auto key_id = 0U;
    auto generated = 0U;
    while (generated < n) {
        auto raw_key = sstring(std::max(min_key_size, sizeof(key_id)), int8_t(0));
        std::copy_n(reinterpret_cast<int8_t*>(&key_id), sizeof(key_id), raw_key.begin());
        auto dk = dht::decorate_key(*s, partition_key::from_single_value(*s, to_bytes(raw_key)));
        key_id++;
        if (shard) {
            if (*shard != shard_of(*s, dk.token())) {
                continue;
            }
        }
        generated++;
        p.emplace_back(std::move(raw_key), std::move(dk));
    }
    boost::sort(p, [&] (auto& p1, auto& p2) {
        return p1.second.less_compare(*s, p2.second);
    });
    return boost::copy_range<std::vector<sstring>>(p | boost::adaptors::map_keys);
}

std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size, local_shard_only lso) {
    return do_make_keys(n, s, min_key_size, lso ? std::optional(this_shard_id()) : std::nullopt);
}

sstables::shared_sstable make_sstable_containing(std::function<sstables::shared_sstable()> sst_factory, std::vector<mutation> muts) {
    tests::reader_concurrency_semaphore_wrapper semaphore;

    auto sst = sst_factory();
    schema_ptr s = muts[0].schema();
    auto mt = make_lw_shared<memtable>(s);

    std::size_t i{0};
    for (auto&& m : muts) {
        mt->apply(m);
        ++i;

        // Give the reactor some time to breathe
        if(i == 10) {
            seastar::thread::yield();
            i = 0;
        }
    }
    write_memtable_to_sstable_for_test(*mt, sst).get();
    sst->open_data().get();

    std::set<mutation, mutation_decorated_key_less_comparator> merged;
    for (auto&& m : muts) {
        auto result = merged.insert(m);
        if (!result.second) {
            auto old = *result.first;
            merged.erase(result.first);
            merged.insert(old + m);
        }
    }

    // validate the sstable
    auto rd = assert_that(sst->as_mutation_source().make_reader(s, semaphore.make_permit()));
    for (auto&& m : merged) {
        rd.produces(m);
    }
    rd.produces_end_of_stream();

    return sst;
}

shared_sstable make_sstable(sstables::test_env& env, schema_ptr s, sstring dir, std::vector<mutation> mutations,
        sstable_writer_config cfg, sstables::sstable::version_types version, gc_clock::time_point query_time) {
    auto mt = make_lw_shared<memtable>(s);
    fs::path dir_path(dir);

    for (auto&& m : mutations) {
        mt->apply(m);
    }

    return make_sstable_easy(env, dir_path, mt, cfg, 1, version, mutations.size(), query_time);
}

shared_sstable make_sstable_easy(test_env& env, const fs::path& path, flat_mutation_reader rd, sstable_writer_config cfg,
        int64_t generation, const sstables::sstable::version_types version, int expected_partition) {
    auto s = rd.schema();
    auto sst = env.make_sstable(s, path.string(), generation, version, sstable_format_types::big);
    sst->write_components(std::move(rd), expected_partition, s, cfg, encoding_stats{}).get();
    sst->load().get();
    return sst;
}

shared_sstable make_sstable_easy(test_env& env, const fs::path& path, lw_shared_ptr<memtable> mt, sstable_writer_config cfg,
        unsigned long gen, const sstable::version_types v, int estimated_partitions, gc_clock::time_point query_time) {
    schema_ptr s = mt->schema();
    auto sst = env.make_sstable(s, path.string(), gen, v, sstable_format_types::big, default_sstable_buffer_size, query_time);
    auto mr = mt->make_flat_reader(s, env.make_reader_permit());
    sst->write_components(std::move(mr), estimated_partitions, s, cfg, mt->get_encoding_stats()).get();
    sst->load().get();
    return sst;
}

std::vector<std::pair<sstring, dht::token>>
token_generation_for_shard(unsigned tokens_to_generate, unsigned shard,
        unsigned ignore_msb, unsigned smp_count) {
    unsigned tokens = 0;
    unsigned key_id = 0;
    std::vector<std::pair<sstring, dht::token>> key_and_token_pair;

    key_and_token_pair.reserve(tokens_to_generate);
    dht::murmur3_partitioner partitioner;
    dht::sharder sharder(smp_count, ignore_msb);

    while (tokens < tokens_to_generate) {
        sstring key = to_sstring(key_id++);
        dht::token token = create_token_from_key(partitioner, key);
        if (shard != sharder.shard_of(token)) {
            continue;
        }
        tokens++;
        key_and_token_pair.emplace_back(key, token);
    }
    assert(key_and_token_pair.size() == tokens_to_generate);

    std::sort(key_and_token_pair.begin(),key_and_token_pair.end(), [] (auto& i, auto& j) {
        return i.second < j.second;
    });

    return key_and_token_pair;
}

future<compaction_result> compact_sstables(sstables::compaction_descriptor descriptor, column_family& cf, std::function<shared_sstable()> creator, compaction_sstable_replacer_fn replacer) {
    descriptor.creator = [creator = std::move(creator)] (shard_id dummy) mutable {
        return creator();
    };
    descriptor.replacer = std::move(replacer);
    auto& cm = cf.get_compaction_manager();
    auto& cdata = compaction_manager_test(cm).register_compaction(descriptor.run_identifier, &cf);
    return sstables::compact_sstables(std::move(descriptor), cdata, cf.as_table_state()).then([&cdata, &cm] (sstables::compaction_result res) {
        compaction_manager_test(cm).deregister_compaction(cdata);
        return res;
    });
}

std::vector<std::pair<sstring, dht::token>> token_generation_for_current_shard(unsigned tokens_to_generate) {
    return token_generation_for_shard(tokens_to_generate, this_shard_id());
}

static sstring toc_filename(const sstring& dir, schema_ptr schema, unsigned int generation, sstable_version_types v) {
    return sstable::filename(dir, schema->ks_name(), schema->cf_name(), v, generation,
                             sstable_format_types::big, component_type::TOC);
}

future<shared_sstable> test_env::reusable_sst(schema_ptr schema, sstring dir, unsigned long generation) {
    for (auto v : boost::adaptors::reverse(all_sstable_versions)) {
        if (co_await file_exists(toc_filename(dir, schema, generation, v))) {
            co_return co_await reusable_sst(schema, dir, generation, v);
        }
    }
    throw sst_not_found(dir, generation);
}

sstables::compaction_data& compaction_manager_test::register_compaction(utils::UUID output_run_id, column_family* cf) {
    auto task = make_lw_shared<compaction_manager::task>(cf, sstables::compaction_type::Compaction);
    testlog.debug("compaction_manager_test: register_compaction: task {} cf={}", fmt::ptr(task.get()), fmt::ptr(cf));
    task->compaction_running = true;
    task->compaction_data = compaction_manager::create_compaction_data();
    task->output_run_identifier = std::move(output_run_id);
    _cm._tasks.push_back(task);
    return task->compaction_data;
}

void compaction_manager_test::deregister_compaction(const sstables::compaction_data& c) {
    auto it = boost::find_if(_cm._tasks, [&c] (auto& task) { return task->compaction_data.compaction_uuid == c.compaction_uuid; });
    if (it != _cm._tasks.end()) {
        auto task = *it;
        testlog.debug("compaction_manager_test: deregister_compaction uuid={}: task {} cf={}", c.compaction_uuid, fmt::ptr(task.get()), fmt::ptr(task->compacting_cf));
        _cm._tasks.erase(it);
    } else {
        testlog.debug("compaction_manager_test: deregister_compaction uuid={}: task not found", c.compaction_uuid);
    }
}
<commit_msg>test: sstable_utils: compact_sstables: deregister compaction also on error path<commit_after>/*
 * Copyright (C) 2017-present ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "test/lib/sstable_utils.hh"

#include "database.hh"
#include "memtable-sstable.hh"
#include "dht/i_partitioner.hh"
#include "dht/murmur3_partitioner.hh"
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/sort.hpp>
#include "sstables/version.hh"
#include "test/lib/flat_mutation_reader_assertions.hh"
#include "test/lib/reader_concurrency_semaphore.hh"
#include <seastar/core/reactor.hh>
#include <seastar/core/seastar.hh>
#include <seastar/core/coroutine.hh>

using namespace sstables;
using namespace std::chrono_literals;

std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size, std::optional<shard_id> shard) {
    std::vector<std::pair<sstring, dht::decorated_key>> p;
    p.reserve(n);

    auto key_id = 0U;
    auto generated = 0U;
    while (generated < n) {
        auto raw_key = sstring(std::max(min_key_size, sizeof(key_id)), int8_t(0));
        std::copy_n(reinterpret_cast<int8_t*>(&key_id), sizeof(key_id), raw_key.begin());
        auto dk = dht::decorate_key(*s, partition_key::from_single_value(*s, to_bytes(raw_key)));
        key_id++;
        if (shard) {
            if (*shard != shard_of(*s, dk.token())) {
                continue;
            }
        }
        generated++;
        p.emplace_back(std::move(raw_key), std::move(dk));
    }
    boost::sort(p, [&] (auto& p1, auto& p2) {
        return p1.second.less_compare(*s, p2.second);
    });
    return boost::copy_range<std::vector<sstring>>(p | boost::adaptors::map_keys);
}

std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size, local_shard_only lso) {
    return do_make_keys(n, s, min_key_size, lso ? std::optional(this_shard_id()) : std::nullopt);
}

sstables::shared_sstable make_sstable_containing(std::function<sstables::shared_sstable()> sst_factory, std::vector<mutation> muts) {
    tests::reader_concurrency_semaphore_wrapper semaphore;

    auto sst = sst_factory();
    schema_ptr s = muts[0].schema();
    auto mt = make_lw_shared<memtable>(s);

    std::size_t i{0};
    for (auto&& m : muts) {
        mt->apply(m);
        ++i;

        // Give the reactor some time to breathe
        if(i == 10) {
            seastar::thread::yield();
            i = 0;
        }
    }
    write_memtable_to_sstable_for_test(*mt, sst).get();
    sst->open_data().get();

    std::set<mutation, mutation_decorated_key_less_comparator> merged;
    for (auto&& m : muts) {
        auto result = merged.insert(m);
        if (!result.second) {
            auto old = *result.first;
            merged.erase(result.first);
            merged.insert(old + m);
        }
    }

    // validate the sstable
    auto rd = assert_that(sst->as_mutation_source().make_reader(s, semaphore.make_permit()));
    for (auto&& m : merged) {
        rd.produces(m);
    }
    rd.produces_end_of_stream();

    return sst;
}

shared_sstable make_sstable(sstables::test_env& env, schema_ptr s, sstring dir, std::vector<mutation> mutations,
        sstable_writer_config cfg, sstables::sstable::version_types version, gc_clock::time_point query_time) {
    auto mt = make_lw_shared<memtable>(s);
    fs::path dir_path(dir);

    for (auto&& m : mutations) {
        mt->apply(m);
    }

    return make_sstable_easy(env, dir_path, mt, cfg, 1, version, mutations.size(), query_time);
}

shared_sstable make_sstable_easy(test_env& env, const fs::path& path, flat_mutation_reader rd, sstable_writer_config cfg,
        int64_t generation, const sstables::sstable::version_types version, int expected_partition) {
    auto s = rd.schema();
    auto sst = env.make_sstable(s, path.string(), generation, version, sstable_format_types::big);
    sst->write_components(std::move(rd), expected_partition, s, cfg, encoding_stats{}).get();
    sst->load().get();
    return sst;
}

shared_sstable make_sstable_easy(test_env& env, const fs::path& path, lw_shared_ptr<memtable> mt, sstable_writer_config cfg,
        unsigned long gen, const sstable::version_types v, int estimated_partitions, gc_clock::time_point query_time) {
    schema_ptr s = mt->schema();
    auto sst = env.make_sstable(s, path.string(), gen, v, sstable_format_types::big, default_sstable_buffer_size, query_time);
    auto mr = mt->make_flat_reader(s, env.make_reader_permit());
    sst->write_components(std::move(mr), estimated_partitions, s, cfg, mt->get_encoding_stats()).get();
    sst->load().get();
    return sst;
}

std::vector<std::pair<sstring, dht::token>>
token_generation_for_shard(unsigned tokens_to_generate, unsigned shard,
        unsigned ignore_msb, unsigned smp_count) {
    unsigned tokens = 0;
    unsigned key_id = 0;
    std::vector<std::pair<sstring, dht::token>> key_and_token_pair;

    key_and_token_pair.reserve(tokens_to_generate);
    dht::murmur3_partitioner partitioner;
    dht::sharder sharder(smp_count, ignore_msb);

    while (tokens < tokens_to_generate) {
        sstring key = to_sstring(key_id++);
        dht::token token = create_token_from_key(partitioner, key);
        if (shard != sharder.shard_of(token)) {
            continue;
        }
        tokens++;
        key_and_token_pair.emplace_back(key, token);
    }
    assert(key_and_token_pair.size() == tokens_to_generate);

    std::sort(key_and_token_pair.begin(),key_and_token_pair.end(), [] (auto& i, auto& j) {
        return i.second < j.second;
    });

    return key_and_token_pair;
}

future<compaction_result> compact_sstables(sstables::compaction_descriptor descriptor, column_family& cf, std::function<shared_sstable()> creator, compaction_sstable_replacer_fn replacer) {
    descriptor.creator = [creator = std::move(creator)] (shard_id dummy) mutable {
        return creator();
    };
    descriptor.replacer = std::move(replacer);
    auto& cm = cf.get_compaction_manager();
    auto& cdata = compaction_manager_test(cm).register_compaction(descriptor.run_identifier, &cf);
    return sstables::compact_sstables(std::move(descriptor), cdata, cf.as_table_state()).then([&cdata, &cm] (sstables::compaction_result res) {
        return res;
    }).finally([&cm, &cdata] {
        compaction_manager_test(cm).deregister_compaction(cdata);
    });
}

std::vector<std::pair<sstring, dht::token>> token_generation_for_current_shard(unsigned tokens_to_generate) {
    return token_generation_for_shard(tokens_to_generate, this_shard_id());
}

static sstring toc_filename(const sstring& dir, schema_ptr schema, unsigned int generation, sstable_version_types v) {
    return sstable::filename(dir, schema->ks_name(), schema->cf_name(), v, generation,
                             sstable_format_types::big, component_type::TOC);
}

future<shared_sstable> test_env::reusable_sst(schema_ptr schema, sstring dir, unsigned long generation) {
    for (auto v : boost::adaptors::reverse(all_sstable_versions)) {
        if (co_await file_exists(toc_filename(dir, schema, generation, v))) {
            co_return co_await reusable_sst(schema, dir, generation, v);
        }
    }
    throw sst_not_found(dir, generation);
}

sstables::compaction_data& compaction_manager_test::register_compaction(utils::UUID output_run_id, column_family* cf) {
    auto task = make_lw_shared<compaction_manager::task>(cf, sstables::compaction_type::Compaction);
    testlog.debug("compaction_manager_test: register_compaction: task {} cf={}", fmt::ptr(task.get()), fmt::ptr(cf));
    task->compaction_running = true;
    task->compaction_data = compaction_manager::create_compaction_data();
    task->output_run_identifier = std::move(output_run_id);
    _cm._tasks.push_back(task);
    return task->compaction_data;
}

void compaction_manager_test::deregister_compaction(const sstables::compaction_data& c) {
    auto it = boost::find_if(_cm._tasks, [&c] (auto& task) { return task->compaction_data.compaction_uuid == c.compaction_uuid; });
    if (it != _cm._tasks.end()) {
        auto task = *it;
        testlog.debug("compaction_manager_test: deregister_compaction uuid={}: task {} cf={}", c.compaction_uuid, fmt::ptr(task.get()), fmt::ptr(task->compacting_cf));
        _cm._tasks.erase(it);
    } else {
        testlog.debug("compaction_manager_test: deregister_compaction uuid={}: task not found", c.compaction_uuid);
    }
}
<|endoftext|>


<commit_before>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.1.2
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.

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 "catch.hpp"

#include <nlohmann/json.hpp>

using nlohmann::json;

bool wstring_is_utf16();
bool wstring_is_utf16()
{
    return (std::wstring(L"💩") == std::wstring(L"\U0001F4A9"));
}

bool u16string_is_utf16();
bool u16string_is_utf16()
{
    return (std::u16string(u"💩") == std::u16string(u"\U0001F4A9"));
}

bool u32string_is_utf32();
bool u32string_is_utf32()
{
    return (std::u32string(U"💩") == std::u32string(U"\U0001F4A9"));
}

TEST_CASE("wide strings")
{
    SECTION("std::wstring")
    {
        if (wstring_is_utf16())
        {
            std::wstring w = L"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }

    SECTION("std::u16string")
    {
        if (u16string_is_utf16())
        {
            std::u16string w = u"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }

    SECTION("std::u32string")
    {
        if (u32string_is_utf32())
        {
            std::u32string w = U"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }
}
<commit_msg>:white_check_mark: improved test coverage #1031<commit_after>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.1.2
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.

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 "catch.hpp"

#include <nlohmann/json.hpp>

using nlohmann::json;

bool wstring_is_utf16();
bool wstring_is_utf16()
{
    return (std::wstring(L"💩") == std::wstring(L"\U0001F4A9"));
}

bool u16string_is_utf16();
bool u16string_is_utf16()
{
    return (std::u16string(u"💩") == std::u16string(u"\U0001F4A9"));
}

bool u32string_is_utf32();
bool u32string_is_utf32()
{
    return (std::u32string(U"💩") == std::u32string(U"\U0001F4A9"));
}

TEST_CASE("wide strings")
{
    SECTION("std::wstring")
    {
        if (wstring_is_utf16())
        {
            std::wstring w = L"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }

    SECTION("invalid std::wstring")
    {
        if (wstring_is_utf16())
        {
            std::wstring w = L"\"\xDBFF";
            CHECK_THROWS_AS(json::parse(w), json::parse_error&);
        }
    }

    SECTION("std::u16string")
    {
        if (u16string_is_utf16())
        {
            std::u16string w = u"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }

    SECTION("invalid std::u16string")
    {
        if (wstring_is_utf16())
        {
            std::u16string w = u"\"\xDBFF";
            CHECK_THROWS_AS(json::parse(w), json::parse_error&);
        }
    }

    SECTION("std::u32string")
    {
        if (u32string_is_utf32())
        {
            std::u32string w = U"[12.2,\"Ⴥaäö💤🧢\"]";
            json j = json::parse(w);
            CHECK(j.dump() == "[12.2,\"Ⴥaäö💤🧢\"]");
        }
    }

    SECTION("invalid std::u32string")
    {
        if (u32string_is_utf32())
        {
            std::u32string w = U"\"\x110000";
            CHECK_THROWS_AS(json::parse(w), json::parse_error&);
        }
    }
}
<|endoftext|>