<commit_before>#include <config.h>
#include <config.h>

#include <dune/stuff/test/test_common.hh>
#include <gtest.h>

#include <string>
#include <array>
#include <initializer_list>
#include <vector>
#include <dune/stuff/common/fixed_map.hh>
#include <dune/stuff/common/string.hh>
#include <dune/stuff/common/ranges.hh>

#include <dune/multiscale/common/main_init.hh>
#include <dune/multiscale/common/error_container.hh>
#include <dune/multiscale/msfem/algorithm.hh>
#include <dune/multiscale/problems/selector.hh>

#include <boost/filesystem.hpp>

using namespace Dune::Stuff::Common;

void set_param();

std::string prepend_test_dir(std::string fn)
{
  boost::filesystem::path path(st_testdata_directory);
  path /= fn;
  return path.string();
}

TEST(MSFEM, All) {
  using namespace Dune::Multiscale;
  using namespace Dune::Multiscale::MsFEM;

  int coarse_grid_level_ = 3;
  int number_of_layers_ = 4;
  int total_refinement_level_ = 5;
  const std::string macroGridName = prepend_test_dir("compare_msfem.dgf");
  set_param();

  //! ---------------------- local error indicators --------------------------------
  // ----- local error indicators (for each coarse grid element T) -------------
  const int max_loop_number = 10;
  ErrorContainer errors(max_loop_number);
  unsigned int loop_number = 0;
  while (algorithm(macroGridName, loop_number++, total_refinement_level_, coarse_grid_level_, number_of_layers_,
                   errors.locals, errors.totals, errors.total_estimated_H1_error_)) {
  }

  for (const auto total : errors.totals) {
    for (auto error : *total) {
      // fails iff 1e-2 <= error
      EXPECT_GT(double(1e-2), error);
    }
  }
}

int main(int argc, char** argv) {
  test_init(argc, argv);
  return RUN_ALL_TESTS();
}

void set_param() {}
<commit_msg>make msfem test compile again<commit_after>#include <config.h>
#include <config.h>

#include <dune/stuff/test/test_common.hh>
#include <gtest.h>

#include <string>
#include <array>
#include <initializer_list>
#include <vector>
#include <dune/stuff/common/fixed_map.hh>
#include <dune/stuff/common/string.hh>
#include <dune/stuff/common/ranges.hh>

#include <dune/multiscale/common/main_init.hh>
#include <dune/multiscale/common/error_container.hh>
#include <dune/multiscale/msfem/algorithm.hh>
#include <dune/multiscale/problems/selector.hh>

#include <boost/filesystem.hpp>

using namespace Dune::Stuff::Common;

void set_param();

std::string prepend_test_dir(std::string fn)
{
  boost::filesystem::path path(st_testdata_directory);
  path /= fn;
  return path.string();
}

TEST(MSFEM, All) {
  using namespace Dune::Multiscale;
  using namespace Dune::Multiscale::MsFEM;

  set_param();

  const auto errors = algorithm();
  for (const auto& err : errors) {
    // fails iff 1e-2 <= error
    EXPECT_GT(double(1e-2), err.second);
  }
}

int main(int argc, char** argv) {
  test_init(argc, argv);
  return RUN_ALL_TESTS();
}

void set_param() {
  DSC_CONFIG.set("grids.macro_cells_per_dim", "[20;20;20]");
  DSC_CONFIG.set("micro_cells_per_macrocell_dim", "[40;40;40]");
  DSC_CONFIG.set("msfem.oversampling_layers", 4);
  DSC_CONFIG.set("global.vtk_output", 0);
  DSC_CONFIG.set("problem.name", "Nine");
}
<|endoftext|>


<commit_before>#ifndef DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH
#define DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#if HAVE_DUNE_GRID

#include <dune/common/fvector.hh>
#include <dune/common/shared_ptr.hh>

#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/io/file/vtk/vtkwriter.hh>
#include <dune/grid/sgrid.hh>

namespace Dune {
namespace Stuff {
namespace Grid {
namespace Provider {

#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::GridSelector::GridType >
#else // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::SGrid< 2, 2 > >
#endif // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
class Interface
{
public:
  typedef GridImp GridType;

  typedef Dune::FieldVector< typename GridType::ctype, GridType::dimension > CoordinateType;

  static const unsigned int dim = GridType::dimension;

  static const std::string id()
  {
    return "stuff.grid.provider";
  }

  virtual Dune::shared_ptr< GridType > grid() = 0;

  virtual const Dune::shared_ptr< const GridType > grid() const = 0;

  //! \todo TODO Remove me in the future (i.e. on 01.01.2013)!
  Dune::shared_ptr< GridType > gridPtr() DUNE_DEPRECATED_MSG("Use grid() instead!")
  {
    return grid();
  }

  //! \todo TODO Remove me in the future (i.e. on 01.01.2013)!
  const Dune::shared_ptr< const GridType > gridPtr() const DUNE_DEPRECATED_MSG("Use grid() instead!")
  {
    return grid();
  }

private:
    typedef typename GridType::LeafGridView GridViewType;

public:
    void visualize(const std::string filename = id() + ".grid") const
    {
      // vtk writer
      GridViewType gridView = grid()->leafView();
      Dune::VTKWriter< GridViewType > vtkwriter(gridView);
      // boundary id
      std::vector< double > boundaryId = generateBoundaryIdVisualization(gridView);
      vtkwriter.addCellData(boundaryId, "boundaryId");
      // codim 0 entity id
      std::vector< double > entityId = generateEntityVisualization(gridView);
      vtkwriter.addCellData(entityId, "entityId");
      // write
      vtkwriter.write(filename, Dune::VTK::ascii);
    } // void visualize(const std::string filename = id + ".grid") const

private:
    std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const
    {
      typedef typename GridViewType::IndexSet::IndexType IndexType;
      typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
      std::vector< double > data(gridView.indexSet().size(0));
      // walk the grid
      for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
           it != gridView.template end< 0 >();
           ++it)
      {
        const EntityType& entity = *it;
        const IndexType& index = gridView.indexSet().index(entity);
        data[index] = 0.0;
        int numberOfBoundarySegments = 0;
        bool isOnBoundary = false;
        for (typename GridViewType::IntersectionIterator intersectionIt = gridView.ibegin(entity);
             intersectionIt != gridView.iend(entity);
             ++intersectionIt) {
          if (!intersectionIt->neighbor() && intersectionIt->boundary()){
            isOnBoundary = true;
            numberOfBoundarySegments += 1;
            data[index] += double(intersectionIt->boundaryId());
          }
        }
        if (isOnBoundary) {
          data[index] /= double(numberOfBoundarySegments);
        }
      } // walk the grid
      return data;
    } // std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const

    std::vector< double > generateEntityVisualization(const GridViewType& gridView) const
    {
      typedef typename GridViewType::IndexSet::IndexType IndexType;
      typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
      std::vector< double > data(gridView.indexSet().size(0));
      // walk the grid
      for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
           it != gridView.template end< 0 >();
           ++it)
      {
        const EntityType& entity = *it;
        const IndexType& index = gridView.indexSet().index(entity);
        data[index] = double(index);
      } // walk the grid
      return data;
    } // std::vector< double > generateEntityVisualization(const GridViewType& gridView) const

}; // class Interface

} // namespace Provider
} // namespace Grid
} // namespace Stuff
} // namespace Dune

#endif // HAVE_DUNE_GRID

#endif // DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH
<commit_msg>[grid.provider] aded create()<commit_after>#ifndef DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH
#define DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH

#ifdef HAVE_CMAKE_CONFIG
  #include "cmake_config.h"
#else
  #include "config.h"
#endif // ifdef HAVE_CMAKE_CONFIG

#if HAVE_DUNE_GRID

#include <dune/common/fvector.hh>
#include <dune/common/shared_ptr.hh>
#include <dune/common/parametertree.hh>

#include <dune/grid/io/file/vtk/vtkwriter.hh>
#include <dune/grid/sgrid.hh>

namespace Dune {
namespace Stuff {
namespace Grid {
namespace Provider {

#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::GridSelector::GridType >
#else // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::SGrid< 2, 2 > >
#endif // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
class Interface
{
public:
  typedef GridImp GridType;

  typedef Interface< GridType > ThisType;

  typedef Dune::FieldVector< typename GridType::ctype, GridType::dimension > CoordinateType;

  static const unsigned int dim = GridType::dimension;

  static const std::string id()
  {
    return "stuff.grid.provider";
  }

  virtual Dune::shared_ptr< GridType > grid() = 0;

  virtual const Dune::shared_ptr< const GridType > grid() const = 0;

  //! \todo TODO Remove me in the future (i.e. on 01.01.2013)!
  Dune::shared_ptr< GridType > gridPtr() DUNE_DEPRECATED_MSG("Use grid() instead!")
  {
    return grid();
  }

  //! \todo TODO Remove me in the future (i.e. on 01.01.2013)!
  const Dune::shared_ptr< const GridType > gridPtr() const DUNE_DEPRECATED_MSG("Use grid() instead!")
  {
    return grid();
  }

private:
    typedef typename GridType::LeafGridView GridViewType;

public:
    void visualize(const std::string filename = id()) const
    {
      // vtk writer
      GridViewType gridView = grid()->leafView();
      Dune::VTKWriter< GridViewType > vtkwriter(gridView);
      // boundary id
      std::vector< double > boundaryId = generateBoundaryIdVisualization(gridView);
      vtkwriter.addCellData(boundaryId, "boundaryId");
      // codim 0 entity id
      std::vector< double > entityId = generateEntityVisualization(gridView);
      vtkwriter.addCellData(entityId, "entityId");
      // write
      vtkwriter.write(filename, Dune::VTK::ascii);
    } // void visualize(const std::string filename = id + ".grid") const

private:
    std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const
    {
      typedef typename GridViewType::IndexSet::IndexType IndexType;
      typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
      std::vector< double > data(gridView.indexSet().size(0));
      // walk the grid
      for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
           it != gridView.template end< 0 >();
           ++it)
      {
        const EntityType& entity = *it;
        const IndexType& index = gridView.indexSet().index(entity);
        data[index] = 0.0;
        int numberOfBoundarySegments = 0;
        bool isOnBoundary = false;
        for (typename GridViewType::IntersectionIterator intersectionIt = gridView.ibegin(entity);
             intersectionIt != gridView.iend(entity);
             ++intersectionIt) {
          if (!intersectionIt->neighbor() && intersectionIt->boundary()){
            isOnBoundary = true;
            numberOfBoundarySegments += 1;
            data[index] += double(intersectionIt->boundaryId());
          }
        }
        if (isOnBoundary) {
          data[index] /= double(numberOfBoundarySegments);
        }
      } // walk the grid
      return data;
    } // std::vector< double > generateBoundaryIdVisualization(const GridViewType& gridView) const

    std::vector< double > generateEntityVisualization(const GridViewType& gridView) const
    {
      typedef typename GridViewType::IndexSet::IndexType IndexType;
      typedef typename GridViewType::template Codim< 0 >::Entity EntityType;
      std::vector< double > data(gridView.indexSet().size(0));
      // walk the grid
      for (typename GridViewType::template Codim< 0 >::Iterator it = gridView.template begin< 0 >();
           it != gridView.template end< 0 >();
           ++it)
      {
        const EntityType& entity = *it;
        const IndexType& index = gridView.indexSet().index(entity);
        data[index] = double(index);
      } // walk the grid
      return data;
    } // std::vector< double > generateEntityVisualization(const GridViewType& gridView) const
}; // class Interface

} // namespace Provider
} // namespace Grid
} // namespace Stuff
} // namespace Dune

#include "cube.hh"
#if HAVE_ALUGRID || HAVE_ALBERTA || HAVE_UG
  #include "gmsh.hh"
#endif // HAVE_ALUGRID || HAVE_ALBERTA || HAVE_UG

namespace Dune {
namespace Stuff {
namespace Grid {
namespace Provider {

#if defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::GridSelector::GridType >
#else // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
template< class GridImp = Dune::SGrid< 2, 2 > >
#endif // defined HAVE_CONFIG_H || defined HAVE_CMAKE_CONFIG
Interface< GridImp >* create(const std::string& type, const Dune::ParameterTree paramTree = Dune::ParameterTree())
{
  // choose provider
  if (type == "stuff.grid.provider.cube") {
    typedef Dune::Stuff::Grid::Provider::Cube<> CubeProviderType;
    CubeProviderType* cubeProvider = new CubeProviderType(CubeProviderType::createFromParamTree(paramTree));
    return cubeProvider;
#if HAVE_ALUGRID || HAVE_ALBERTA || HAVE_UG
  } else if (type == "stuff.grid.provider.gmsh") {
    typedef Dune::Stuff::Grid::Provider::Gmsh<> GmshProviderType;
    GmshProviderType* gmshProvider = new GmshProviderType(GmshProviderType::createFromParamTree(paramTree));
    return gmshProvider;
#endif // HAVE_ALUGRID || HAVE_ALBERTA || HAVE_UG
  } else
    DUNE_THROW(Dune::RangeError,
               "\nError: unknown grid provider '" << type << "' requested");

} // Interface< GridImp >* create(const std::string& type, const Dune::ParameterTree paramTree = Dune::ParameterTree())

} // namespace Provider
} // namespace Grid
} // namespace Stuff
} // namespace Dune

#endif // HAVE_DUNE_GRID

#endif // DUNE_STUFF_GRID_PROVIDER_INTERFACE_HH
<|endoftext|>


<commit_before>#include "json_ui.hh"

#include "containers.hh"
#include "display_buffer.hh"
#include "keys.hh"
#include "file.hh"
#include "event_manager.hh"
#include "value.hh"
#include "unit_tests.hh"

#include <utility>

#include <unistd.h>

namespace Kakoune
{

template<typename T>
String to_json(ArrayView<const T> array)
{
    String res;
    for (auto& elem : array)
    {
        if (not res.empty())
            res += ", ";
        res += to_json(elem);
    }
    return "[" + res + "]";
}

template<typename T, MemoryDomain D>
String to_json(const Vector<T, D>& vec) { return to_json(ArrayView<const T>{vec}); }

String to_json(int i) { return to_string(i); }
String to_json(bool b) { return b ? "true" : "false"; }
String to_json(StringView str)
{
    String res;
    res.reserve(str.length() + 4);
    res += '"';
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find_if(it, end, [](char c) {
            return c == '\\' or c == '"' or (c >= 0 and c <= 0x1F);
        });

        res += StringView{it, next};
        if (next == end)
            break;

        char buf[7] = {'\\', *next, 0};
        if (*next >= 0 and *next <= 0x1F)
            sprintf(buf, "\\u%04x", *next);

        res += buf;
        it = next+1;
    }
    res += '"';
    return res;
}

String to_json(Color color)
{
    if (color.color == Kakoune::Color::RGB)
    {
        char buffer[10];
        sprintf(buffer, R"("#%02x%02x%02x")", color.r, color.g, color.b);
        return buffer;
    }
    return to_json(color_to_str(color));
}

String to_json(Attribute attributes)
{
    struct { Attribute attr; StringView name; }
    attrs[] {
        { Attribute::Exclusive, "exclusive" },
        { Attribute::Underline, "underline" },
        { Attribute::Reverse, "reverse" },
        { Attribute::Blink, "blink" },
        { Attribute::Bold, "bold" },
        { Attribute::Dim, "dim" },
        { Attribute::Italic, "italic" },
    };

    String res;
    for (auto& attr : attrs)
    {
        if (not (attributes & attr.attr))
            continue;

        if (not res.empty())
            res += ", ";
        res += to_json(attr.name);
    }
    return "[" + res + "]";
}

String to_json(Face face)
{
    return format(R"(\{ "fg": {}, "bg": {}, "attributes": {} })",
                  to_json(face.fg), to_json(face.bg), to_json(face.attributes));
}

String to_json(const DisplayAtom& atom)
{
    return format(R"(\{ "face": {}, "contents": {} })", to_json(atom.face), to_json(atom.content()));
}

String to_json(const DisplayLine& line)
{
    return to_json(line.atoms());
}

String to_json(CharCoord coord)
{
    return format(R"(\{ "line": {}, "column": {} })", coord.line, coord.column);
}

String to_json(MenuStyle style)
{
    switch (style)
    {
        case MenuStyle::Prompt: return R"("prompt")";
        case MenuStyle::Inline: return R"("inline")";
    }
    return "";
}

String to_json(InfoStyle style)
{
    switch (style)
    {
        case InfoStyle::Prompt: return R"("prompt")";
        case InfoStyle::Inline: return R"("inline")";
        case InfoStyle::InlineAbove: return R"("inlineAbove")";
        case InfoStyle::InlineBelow: return R"("inlineBelow")";
        case InfoStyle::MenuDoc: return R"("menuDoc")";
    }
    return "";
}

String concat()
{
    return "";
}

template<typename First, typename... Args>
String concat(First&& first, Args&&... args)
{
    if (sizeof...(Args) != 0)
        return to_json(first) + ", " + concat(args...);
    return to_json(first);
}

template<typename... Args>
void rpc_call(StringView method, Args&&... args)
{
    auto q = format(R"(\{ "jsonrpc": "2.0", "method": "{}", "params": [{}] }{})",
                    method, concat(std::forward<Args>(args)...), "\n");

    write_stdout(q);
}

JsonUI::JsonUI()
    : m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) {
        parse_requests(mode);
      }}, m_dimensions{24, 80}
{
    set_signal_handler(SIGINT, SIG_DFL);
}

void JsonUI::draw(const DisplayBuffer& display_buffer,
                  const Face& default_face, const Face& padding_face)
{
    rpc_call("draw", display_buffer.lines(), default_face, padding_face);
}

void JsonUI::draw_status(const DisplayLine& status_line,
                         const DisplayLine& mode_line,
                         const Face& default_face)
{
    rpc_call("draw_status", status_line, mode_line, default_face);
}

bool JsonUI::is_key_available()
{
    return not m_pending_keys.empty();
}

Key JsonUI::get_key()
{
    kak_assert(not m_pending_keys.empty());
    Key key = m_pending_keys.front();
    m_pending_keys.erase(m_pending_keys.begin());
    return key;
}

void JsonUI::menu_show(ConstArrayView<DisplayLine> items,
                       CharCoord anchor, Face fg, Face bg,
                       MenuStyle style)
{
    rpc_call("menu_show", items, anchor, fg, bg, style);
}

void JsonUI::menu_select(int selected)
{
    rpc_call("menu_show", selected);
}

void JsonUI::menu_hide()
{
    rpc_call("menu_hide");
}

void JsonUI::info_show(StringView title, StringView content,
                       CharCoord anchor, Face face,
                       InfoStyle style)
{
    rpc_call("info_show", title, content, anchor, face, style);
}

void JsonUI::info_hide()
{
    rpc_call("info_hide");
}

void JsonUI::refresh(bool force)
{
    rpc_call("refresh", force);
}

void JsonUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

void JsonUI::set_ui_options(const Options& options)
{
    // rpc_call("set_ui_options", options);
}

CharCoord JsonUI::dimensions()
{
    return m_dimensions;
}

using JsonArray = Vector<Value>;
using JsonObject = IdMap<Value>;

static bool is_digit(char c) { return c >= '0' and c <= '9'; }

std::tuple<Value, const char*>
parse_json(const char* pos, const char* end)
{
    using Result = std::tuple<Value, const char*>;

    if (not skip_while(pos, end, is_blank))
        return {};

    if (is_digit(*pos))
    {
        auto digit_end = pos;
        skip_while(digit_end, end, is_digit);
        return Result{ Value{str_to_int({pos, digit_end})}, digit_end };
    }
    if (end - pos > 4 and StringView{pos, pos+4} == "true")
        return Result{ Value{true}, pos+4 };
    if (end - pos > 5 and StringView{pos, pos+5} == "false")
        return Result{ Value{false}, pos+5 };
    if (*pos == '"')
    {
        String value;
        bool escaped = false;
        ++pos;
        for (auto string_end = pos; string_end != end; ++string_end)
        {
            if (escaped)
            {
                escaped = false;
                value += StringView{pos, string_end};
                value.back() = *string_end;
                pos = string_end+1;
                continue;
            }
            if (*string_end == '\\')
                escaped = true;
            if (*string_end == '"')
            {
                value += StringView{pos, string_end};
                return Result{std::move(value), string_end+1};
            }
        }
        return {};
    }
    if (*pos == '[')
    {
        JsonArray array;
        if (*++pos == ']')
            return Result{std::move(array), pos+1};

        while (true)
        {
            Value element;
            std::tie(element, pos) = parse_json(pos, end);
            if (not element)
                return {};
            array.push_back(std::move(element));
            if (not skip_while(pos, end, is_blank))
                return {};

            if (*pos == ',')
                ++pos;
            else if (*pos == ']')
                return Result{std::move(array), pos+1};
            else
                throw runtime_error("unable to parse array, expected ',' or ']'");
        }
    }
    if (*pos == '{')
    {
        JsonObject object;
        if (*++pos == '}')
            return Result{std::move(object), pos+1};

        while (true)
        {
            Value name_value;
            std::tie(name_value, pos) = parse_json(pos, end);
            if (not name_value)
                return {};

            String& name = name_value.as<String>();
            if (not skip_while(pos, end, is_blank))
                return {};
            if (*pos++ != ':')
                throw runtime_error("expected :");

            Value element;
            std::tie(element, pos) = parse_json(pos, end);
            if (not element)
                return {};
            object.append({ std::move(name), std::move(element) });
            if (not skip_while(pos, end, is_blank))
                return {};

            if (*pos == ',')
                ++pos;
            else if (*pos == '}')
                return Result{std::move(object), pos+1};
            else
                throw runtime_error("unable to parse object, expected ',' or '}'");
        }
    }
    throw runtime_error("Could not parse json");
}

std::tuple<Value, const char*>
parse_json(StringView json) { return parse_json(json.begin(), json.end()); }

void JsonUI::eval_json(const Value& json)
{
    if (not json.is_a<JsonObject>())
        throw runtime_error("json request is not an object");

    const JsonObject& object = json.as<JsonObject>();
    auto json_it = object.find("jsonrpc");
    if (json_it == object.end() or json_it->value.as<String>() != "2.0")
        throw runtime_error("invalid json rpc request");

    auto method_it = object.find("method");
    if (method_it == object.end())
        throw runtime_error("invalid json rpc request (method missing)");
    StringView method = method_it->value.as<String>();

    auto params_it = object.find("params");
    if (params_it == object.end())
        throw runtime_error("invalid json rpc request (params missing)");
    const JsonArray& params = params_it->value.as<JsonArray>();

    if (method == "keys")
    {
        for (auto& key_val : params)
        {
            for (auto& key : parse_keys(key_val.as<String>()))
                m_pending_keys.push_back(key);
        }
    }
    else if (method == "resize")
    {
        if (params.size() != 2)
            throw runtime_error("resize expects 2 parameters");

        CharCoord dim{params[0].as<int>(), params[1].as<int>()};
        m_dimensions = dim;
        m_pending_keys.push_back(resize(dim));
    }
    else
        throw runtime_error("unknown method");
}

static bool stdin_ready()
{
    fd_set  rfds;
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 0;

    return select(1, &rfds, nullptr, nullptr, &tv) == 1;
}

void JsonUI::parse_requests(EventMode mode)
{
    constexpr size_t bufsize = 1024;
    char buf[bufsize];
    while (stdin_ready())
    {
        ssize_t size = ::read(0, buf, bufsize);
        if (size == -1 or size == 0)
            break;

        m_requests += StringView{buf, buf + size};
    }

    while (not m_requests.empty())
    {
        const char* pos = nullptr;
        try
        {
            Value json;
            std::tie(json, pos) = parse_json(m_requests);
            if (json)
                eval_json(json);
        }
        catch (runtime_error& error)
        {
            write_stderr(format("error while handling requests '{}': '{}'",
                                m_requests, error.what()));
            // try to salvage request by dropping its first line
            pos = std::min(m_requests.end(), find(m_requests, '\n')+1);
        }
        if (not pos)
            break; // unterminated request ?

        m_requests = String{pos, m_requests.end()};
    }

    while (m_input_callback and not m_pending_keys.empty())
        m_input_callback(mode);
}

UnitTest test_json_parser{[]()
{
    {
        auto value = std::get<0>(parse_json(R"({ "jsonrpc": "2.0", "method": "keys", "params": [ "b", "l", "a", "h" ] })"));
        kak_assert(value);
    }

    {
        auto value = std::get<0>(parse_json("[10,20]"));
        kak_assert(value and value.is_a<JsonArray>());
        kak_assert(value.as<JsonArray>().at(1).as<int>() == 20);
    }

    {
        auto value = std::get<0>(parse_json("{}"));
        kak_assert(value and value.is_a<JsonObject>());
        kak_assert(value.as<JsonObject>().empty());
    }
}};

}
<commit_msg>Fix menu_select in the JSON ui<commit_after>#include "json_ui.hh"

#include "containers.hh"
#include "display_buffer.hh"
#include "keys.hh"
#include "file.hh"
#include "event_manager.hh"
#include "value.hh"
#include "unit_tests.hh"

#include <utility>

#include <unistd.h>

namespace Kakoune
{

template<typename T>
String to_json(ArrayView<const T> array)
{
    String res;
    for (auto& elem : array)
    {
        if (not res.empty())
            res += ", ";
        res += to_json(elem);
    }
    return "[" + res + "]";
}

template<typename T, MemoryDomain D>
String to_json(const Vector<T, D>& vec) { return to_json(ArrayView<const T>{vec}); }

String to_json(int i) { return to_string(i); }
String to_json(bool b) { return b ? "true" : "false"; }
String to_json(StringView str)
{
    String res;
    res.reserve(str.length() + 4);
    res += '"';
    for (auto it = str.begin(), end = str.end(); it != end; )
    {
        auto next = std::find_if(it, end, [](char c) {
            return c == '\\' or c == '"' or (c >= 0 and c <= 0x1F);
        });

        res += StringView{it, next};
        if (next == end)
            break;

        char buf[7] = {'\\', *next, 0};
        if (*next >= 0 and *next <= 0x1F)
            sprintf(buf, "\\u%04x", *next);

        res += buf;
        it = next+1;
    }
    res += '"';
    return res;
}

String to_json(Color color)
{
    if (color.color == Kakoune::Color::RGB)
    {
        char buffer[10];
        sprintf(buffer, R"("#%02x%02x%02x")", color.r, color.g, color.b);
        return buffer;
    }
    return to_json(color_to_str(color));
}

String to_json(Attribute attributes)
{
    struct { Attribute attr; StringView name; }
    attrs[] {
        { Attribute::Exclusive, "exclusive" },
        { Attribute::Underline, "underline" },
        { Attribute::Reverse, "reverse" },
        { Attribute::Blink, "blink" },
        { Attribute::Bold, "bold" },
        { Attribute::Dim, "dim" },
        { Attribute::Italic, "italic" },
    };

    String res;
    for (auto& attr : attrs)
    {
        if (not (attributes & attr.attr))
            continue;

        if (not res.empty())
            res += ", ";
        res += to_json(attr.name);
    }
    return "[" + res + "]";
}

String to_json(Face face)
{
    return format(R"(\{ "fg": {}, "bg": {}, "attributes": {} })",
                  to_json(face.fg), to_json(face.bg), to_json(face.attributes));
}

String to_json(const DisplayAtom& atom)
{
    return format(R"(\{ "face": {}, "contents": {} })", to_json(atom.face), to_json(atom.content()));
}

String to_json(const DisplayLine& line)
{
    return to_json(line.atoms());
}

String to_json(CharCoord coord)
{
    return format(R"(\{ "line": {}, "column": {} })", coord.line, coord.column);
}

String to_json(MenuStyle style)
{
    switch (style)
    {
        case MenuStyle::Prompt: return R"("prompt")";
        case MenuStyle::Inline: return R"("inline")";
    }
    return "";
}

String to_json(InfoStyle style)
{
    switch (style)
    {
        case InfoStyle::Prompt: return R"("prompt")";
        case InfoStyle::Inline: return R"("inline")";
        case InfoStyle::InlineAbove: return R"("inlineAbove")";
        case InfoStyle::InlineBelow: return R"("inlineBelow")";
        case InfoStyle::MenuDoc: return R"("menuDoc")";
    }
    return "";
}

String concat()
{
    return "";
}

template<typename First, typename... Args>
String concat(First&& first, Args&&... args)
{
    if (sizeof...(Args) != 0)
        return to_json(first) + ", " + concat(args...);
    return to_json(first);
}

template<typename... Args>
void rpc_call(StringView method, Args&&... args)
{
    auto q = format(R"(\{ "jsonrpc": "2.0", "method": "{}", "params": [{}] }{})",
                    method, concat(std::forward<Args>(args)...), "\n");

    write_stdout(q);
}

JsonUI::JsonUI()
    : m_stdin_watcher{0, [this](FDWatcher&, EventMode mode) {
        parse_requests(mode);
      }}, m_dimensions{24, 80}
{
    set_signal_handler(SIGINT, SIG_DFL);
}

void JsonUI::draw(const DisplayBuffer& display_buffer,
                  const Face& default_face, const Face& padding_face)
{
    rpc_call("draw", display_buffer.lines(), default_face, padding_face);
}

void JsonUI::draw_status(const DisplayLine& status_line,
                         const DisplayLine& mode_line,
                         const Face& default_face)
{
    rpc_call("draw_status", status_line, mode_line, default_face);
}

bool JsonUI::is_key_available()
{
    return not m_pending_keys.empty();
}

Key JsonUI::get_key()
{
    kak_assert(not m_pending_keys.empty());
    Key key = m_pending_keys.front();
    m_pending_keys.erase(m_pending_keys.begin());
    return key;
}

void JsonUI::menu_show(ConstArrayView<DisplayLine> items,
                       CharCoord anchor, Face fg, Face bg,
                       MenuStyle style)
{
    rpc_call("menu_show", items, anchor, fg, bg, style);
}

void JsonUI::menu_select(int selected)
{
    rpc_call("menu_select", selected);
}

void JsonUI::menu_hide()
{
    rpc_call("menu_hide");
}

void JsonUI::info_show(StringView title, StringView content,
                       CharCoord anchor, Face face,
                       InfoStyle style)
{
    rpc_call("info_show", title, content, anchor, face, style);
}

void JsonUI::info_hide()
{
    rpc_call("info_hide");
}

void JsonUI::refresh(bool force)
{
    rpc_call("refresh", force);
}

void JsonUI::set_input_callback(InputCallback callback)
{
    m_input_callback = std::move(callback);
}

void JsonUI::set_ui_options(const Options& options)
{
    // rpc_call("set_ui_options", options);
}

CharCoord JsonUI::dimensions()
{
    return m_dimensions;
}

using JsonArray = Vector<Value>;
using JsonObject = IdMap<Value>;

static bool is_digit(char c) { return c >= '0' and c <= '9'; }

std::tuple<Value, const char*>
parse_json(const char* pos, const char* end)
{
    using Result = std::tuple<Value, const char*>;

    if (not skip_while(pos, end, is_blank))
        return {};

    if (is_digit(*pos))
    {
        auto digit_end = pos;
        skip_while(digit_end, end, is_digit);
        return Result{ Value{str_to_int({pos, digit_end})}, digit_end };
    }
    if (end - pos > 4 and StringView{pos, pos+4} == "true")
        return Result{ Value{true}, pos+4 };
    if (end - pos > 5 and StringView{pos, pos+5} == "false")
        return Result{ Value{false}, pos+5 };
    if (*pos == '"')
    {
        String value;
        bool escaped = false;
        ++pos;
        for (auto string_end = pos; string_end != end; ++string_end)
        {
            if (escaped)
            {
                escaped = false;
                value += StringView{pos, string_end};
                value.back() = *string_end;
                pos = string_end+1;
                continue;
            }
            if (*string_end == '\\')
                escaped = true;
            if (*string_end == '"')
            {
                value += StringView{pos, string_end};
                return Result{std::move(value), string_end+1};
            }
        }
        return {};
    }
    if (*pos == '[')
    {
        JsonArray array;
        if (*++pos == ']')
            return Result{std::move(array), pos+1};

        while (true)
        {
            Value element;
            std::tie(element, pos) = parse_json(pos, end);
            if (not element)
                return {};
            array.push_back(std::move(element));
            if (not skip_while(pos, end, is_blank))
                return {};

            if (*pos == ',')
                ++pos;
            else if (*pos == ']')
                return Result{std::move(array), pos+1};
            else
                throw runtime_error("unable to parse array, expected ',' or ']'");
        }
    }
    if (*pos == '{')
    {
        JsonObject object;
        if (*++pos == '}')
            return Result{std::move(object), pos+1};

        while (true)
        {
            Value name_value;
            std::tie(name_value, pos) = parse_json(pos, end);
            if (not name_value)
                return {};

            String& name = name_value.as<String>();
            if (not skip_while(pos, end, is_blank))
                return {};
            if (*pos++ != ':')
                throw runtime_error("expected :");

            Value element;
            std::tie(element, pos) = parse_json(pos, end);
            if (not element)
                return {};
            object.append({ std::move(name), std::move(element) });
            if (not skip_while(pos, end, is_blank))
                return {};

            if (*pos == ',')
                ++pos;
            else if (*pos == '}')
                return Result{std::move(object), pos+1};
            else
                throw runtime_error("unable to parse object, expected ',' or '}'");
        }
    }
    throw runtime_error("Could not parse json");
}

std::tuple<Value, const char*>
parse_json(StringView json) { return parse_json(json.begin(), json.end()); }

void JsonUI::eval_json(const Value& json)
{
    if (not json.is_a<JsonObject>())
        throw runtime_error("json request is not an object");

    const JsonObject& object = json.as<JsonObject>();
    auto json_it = object.find("jsonrpc");
    if (json_it == object.end() or json_it->value.as<String>() != "2.0")
        throw runtime_error("invalid json rpc request");

    auto method_it = object.find("method");
    if (method_it == object.end())
        throw runtime_error("invalid json rpc request (method missing)");
    StringView method = method_it->value.as<String>();

    auto params_it = object.find("params");
    if (params_it == object.end())
        throw runtime_error("invalid json rpc request (params missing)");
    const JsonArray& params = params_it->value.as<JsonArray>();

    if (method == "keys")
    {
        for (auto& key_val : params)
        {
            for (auto& key : parse_keys(key_val.as<String>()))
                m_pending_keys.push_back(key);
        }
    }
    else if (method == "resize")
    {
        if (params.size() != 2)
            throw runtime_error("resize expects 2 parameters");

        CharCoord dim{params[0].as<int>(), params[1].as<int>()};
        m_dimensions = dim;
        m_pending_keys.push_back(resize(dim));
    }
    else
        throw runtime_error("unknown method");
}

static bool stdin_ready()
{
    fd_set  rfds;
    FD_ZERO(&rfds);
    FD_SET(0, &rfds);

    timeval tv;
    tv.tv_sec = 0;
    tv.tv_usec = 0;

    return select(1, &rfds, nullptr, nullptr, &tv) == 1;
}

void JsonUI::parse_requests(EventMode mode)
{
    constexpr size_t bufsize = 1024;
    char buf[bufsize];
    while (stdin_ready())
    {
        ssize_t size = ::read(0, buf, bufsize);
        if (size == -1 or size == 0)
            break;

        m_requests += StringView{buf, buf + size};
    }

    while (not m_requests.empty())
    {
        const char* pos = nullptr;
        try
        {
            Value json;
            std::tie(json, pos) = parse_json(m_requests);
            if (json)
                eval_json(json);
        }
        catch (runtime_error& error)
        {
            write_stderr(format("error while handling requests '{}': '{}'",
                                m_requests, error.what()));
            // try to salvage request by dropping its first line
            pos = std::min(m_requests.end(), find(m_requests, '\n')+1);
        }
        if (not pos)
            break; // unterminated request ?

        m_requests = String{pos, m_requests.end()};
    }

    while (m_input_callback and not m_pending_keys.empty())
        m_input_callback(mode);
}

UnitTest test_json_parser{[]()
{
    {
        auto value = std::get<0>(parse_json(R"({ "jsonrpc": "2.0", "method": "keys", "params": [ "b", "l", "a", "h" ] })"));
        kak_assert(value);
    }

    {
        auto value = std::get<0>(parse_json("[10,20]"));
        kak_assert(value and value.is_a<JsonArray>());
        kak_assert(value.as<JsonArray>().at(1).as<int>() == 20);
    }

    {
        auto value = std::get<0>(parse_json("{}"));
        kak_assert(value and value.is_a<JsonObject>());
        kak_assert(value.as<JsonObject>().empty());
    }
}};

}
<|endoftext|>


<commit_before>#include "aerial_autonomy/controller_hardware_connectors/visual_servoing_controller_drone_connector.h"

PositionYaw VisualServoingControllerDroneConnector::extractSensorData() {
  parsernode::common::quaddata quad_data;
  drone_hardware_.getquaddata(quad_data);
  tf::Vector3 tracking_position = getTrackingVectorGlobalFrame();
  return PositionYaw(tracking_position.getX(), tracking_position.getY(),
                     tracking_position.getZ(), quad_data.rpydata.z);
}

void VisualServoingControllerDroneConnector::sendHardwareCommands(
    VelocityYawRate controls) {
  geometry_msgs::Vector3 velocity_cmd;
  velocity_cmd.x = controls.x;
  velocity_cmd.y = controls.y;
  velocity_cmd.z = controls.z;
  drone_hardware_.cmdvelguided(velocity_cmd, controls.yaw_rate);
}

tf::Vector3
VisualServoingControllerDroneConnector::getTrackingVectorGlobalFrame() {
  Position object_position_cam;
  if (!roi_to_position_converter_.getObjectPosition(object_position_cam)) {
    /// \todo(Matt) handle case when cannot get object position
  }
  tf::Vector3 object_direction_cam(object_position_cam.x, object_position_cam.y,
                                   object_position_cam.z);
  // Convert from camera frame to global frame
  return (getBodyFrameRotation() *
          (camera_transform_.getBasis() * object_direction_cam))
      .normalize();
}

tf::Matrix3x3 VisualServoingControllerDroneConnector::getBodyFrameRotation() {
  parsernode::common::quaddata quad_data;
  drone_hardware_.getquaddata(quad_data);
  return tf::Matrix3x3(tf::createQuaternionFromRPY(
      quad_data.rpydata.x, quad_data.rpydata.y, quad_data.rpydata.z));
}
<commit_msg>Add TODO<commit_after>#include "aerial_autonomy/controller_hardware_connectors/visual_servoing_controller_drone_connector.h"

PositionYaw VisualServoingControllerDroneConnector::extractSensorData() {
  parsernode::common::quaddata quad_data;
  drone_hardware_.getquaddata(quad_data);
  tf::Vector3 tracking_position = getTrackingVectorGlobalFrame();
  return PositionYaw(tracking_position.getX(), tracking_position.getY(),
                     tracking_position.getZ(), quad_data.rpydata.z);
}

void VisualServoingControllerDroneConnector::sendHardwareCommands(
    VelocityYawRate controls) {
  geometry_msgs::Vector3 velocity_cmd;
  velocity_cmd.x = controls.x;
  velocity_cmd.y = controls.y;
  velocity_cmd.z = controls.z;
  drone_hardware_.cmdvelguided(velocity_cmd, controls.yaw_rate);
  /// \todo Gowtham Add function for commanding velocity with yaw rate
}

tf::Vector3
VisualServoingControllerDroneConnector::getTrackingVectorGlobalFrame() {
  Position object_position_cam;
  if (!roi_to_position_converter_.getObjectPosition(object_position_cam)) {
    /// \todo(Matt) handle case when cannot get object position
  }
  tf::Vector3 object_direction_cam(object_position_cam.x, object_position_cam.y,
                                   object_position_cam.z);
  // Convert from camera frame to global frame
  return (getBodyFrameRotation() *
          (camera_transform_.getBasis() * object_direction_cam))
      .normalize();
}

tf::Matrix3x3 VisualServoingControllerDroneConnector::getBodyFrameRotation() {
  parsernode::common::quaddata quad_data;
  drone_hardware_.getquaddata(quad_data);
  return tf::Matrix3x3(tf::createQuaternionFromRPY(
      quad_data.rpydata.x, quad_data.rpydata.y, quad_data.rpydata.z));
}
<|endoftext|>


<commit_before>// Copyright 2021 The Cross-Media Measurement Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wfa/virtual_people/core/model/utils/distributed_consistent_hashing.h"

#include <cmath>

#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "src/farmhash.h"

namespace wfa_virtual_people {

absl::StatusOr<std::unique_ptr<DistributedConsistentHashing>>
DistributedConsistentHashing::Build(
    std::unique_ptr<std::vector<DistributionChoice>> distribution) {
  if (distribution->empty()) {
    return absl::InvalidArgumentError("The given distribution is empty.");
  }
  // Returns error status for any negative probability.
  auto negative_probability_it = std::find_if(
      distribution->begin(), distribution->end(),
      [](const DistributionChoice& choice) {
        return (choice.probability < 0);
      });
  if (negative_probability_it != distribution->end()) {
    return absl::InvalidArgumentError("Negative probability is provided.");
  }

  // Gets sum of probabilities.
  double probabilities_sum = 0.0;
  std::for_each (distribution->begin(), distribution->end(),
                 [&probabilities_sum](const DistributionChoice& choice) {
    probabilities_sum += choice.probability;
  });
  if (probabilities_sum <= 0) {
    return absl::InvalidArgumentError("Probabilities sum is not positive.");
  }
  // Normalizes the probabilities.
  std::for_each (distribution->begin(), distribution->end(),
                 [probabilities_sum](DistributionChoice& choice) {
    choice.probability /= probabilities_sum;
  });
  return absl::make_unique<DistributedConsistentHashing>(
      std::move(distribution));
}

std::string GetFullSeed(
    absl::string_view random_seed, const int32_t choice) {
  return absl::StrFormat("consistent-hashing-%s-%d", random_seed, choice);
}

inline double FloatHash(absl::string_view full_seed) {
  return static_cast<double>(util::Fingerprint64(full_seed)) /
         static_cast<double>(std::numeric_limits<uint64_t>::max());
}

double ComputeXi(
    absl::string_view random_seed,
    const int32_t choice, const double probability) {
  return (-std::log(FloatHash(GetFullSeed(random_seed, choice))) /
          probability);
}

// A C++ version of the Python function ConsistentHashing.hash in
// https://github.com/world-federation-of-advertisers/virtual_people_examples/blob/main/notebooks/Consistent_Hashing.ipynb
int32_t DistributedConsistentHashing::Hash(
    absl::string_view random_seed) const {
  auto it = distribution_->begin();
  int32_t choice = it->choice_id;
  double choice_xi = ComputeXi(random_seed, it->choice_id, it->probability);
  for (++it; it != distribution_->end(); ++it) {
    double xi = ComputeXi(random_seed, it->choice_id, it->probability);
    if (choice_xi > xi) {
      choice = it->choice_id;
      choice_xi = xi;
    }
  }
  return choice;
}

}  // namespace wfa_virtual_people
<commit_msg>Use for-each loop instead of std::for_each and std::find_if.<commit_after>// Copyright 2021 The Cross-Media Measurement Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "wfa/virtual_people/core/model/utils/distributed_consistent_hashing.h"

#include <cmath>

#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "src/farmhash.h"

namespace wfa_virtual_people {

absl::StatusOr<std::unique_ptr<DistributedConsistentHashing>>
DistributedConsistentHashing::Build(
    std::unique_ptr<std::vector<DistributionChoice>> distribution) {
  if (distribution->empty()) {
    return absl::InvalidArgumentError("The given distribution is empty.");
  }
  // Returns error status for any negative probability, and gets sum of
  // probabilities.
  double probabilities_sum = 0.0;
  for (const DistributionChoice& choice : *distribution) {
    if (choice.probability < 0) {
      return absl::InvalidArgumentError("Negative probability is provided.");
    }
    probabilities_sum += choice.probability;
  }

  if (probabilities_sum <= 0) {
    return absl::InvalidArgumentError("Probabilities sum is not positive.");
  }
  // Normalizes the probabilities.
  for (DistributionChoice& choice : *distribution) {
    choice.probability /= probabilities_sum;
  }
  return absl::make_unique<DistributedConsistentHashing>(
      std::move(distribution));
}

std::string GetFullSeed(
    absl::string_view random_seed, const int32_t choice) {
  return absl::StrFormat("consistent-hashing-%s-%d", random_seed, choice);
}

inline double FloatHash(absl::string_view full_seed) {
  return static_cast<double>(util::Fingerprint64(full_seed)) /
         static_cast<double>(std::numeric_limits<uint64_t>::max());
}

double ComputeXi(
    absl::string_view random_seed,
    const int32_t choice, const double probability) {
  return (-std::log(FloatHash(GetFullSeed(random_seed, choice))) /
          probability);
}

// A C++ version of the Python function ConsistentHashing.hash in
// https://github.com/world-federation-of-advertisers/virtual_people_examples/blob/main/notebooks/Consistent_Hashing.ipynb
int32_t DistributedConsistentHashing::Hash(
    absl::string_view random_seed) const {
  auto it = distribution_->begin();
  int32_t choice = it->choice_id;
  double choice_xi = ComputeXi(random_seed, it->choice_id, it->probability);
  for (++it; it != distribution_->end(); ++it) {
    double xi = ComputeXi(random_seed, it->choice_id, it->probability);
    if (choice_xi > xi) {
      choice = it->choice_id;
      choice_xi = xi;
    }
  }
  return choice;
}

}  // namespace wfa_virtual_people
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2013 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <functional>

#include "ep_engine.h"
#include "flusher.h"
#include "kvshard.h"

KVShard::KVShard(uint16_t id, EventuallyPersistentStore &store) :
    shardId(id), highPrioritySnapshot(false),
    lowPrioritySnapshot(false),
    kvConfig(store.getEPEngine().getConfiguration(), shardId),
    highPriorityCount(0)
{
    EPStats &stats = store.getEPEngine().getEpStats();
    Configuration &config = store.getEPEngine().getConfiguration();
    maxVbuckets = config.getMaxVbuckets();

    vbuckets = new RCPtr<VBucket>[maxVbuckets];

    std::string backend = kvConfig.getBackend();
    uint16_t commitInterval = 1;

    if (backend.compare("couchdb") == 0) {
        rwUnderlying = KVStoreFactory::create(kvConfig, false);
        roUnderlying = KVStoreFactory::create(kvConfig, true);
    } else if (backend.compare("forestdb") == 0) {
        rwUnderlying = KVStoreFactory::create(kvConfig);
        roUnderlying = rwUnderlying;
        commitInterval = config.getMaxVbuckets()/config.getMaxNumShards();
    }

    flusher = new Flusher(&store, this, commitInterval);
    bgFetcher = new BgFetcher(&store, this, stats);
}

KVShard::~KVShard() {
    if (flusher->state() != stopped) {
        flusher->stop(true);
        LOG(EXTENSION_LOG_WARNING, "Terminating flusher while it is in %s",
            flusher->stateName());
    }
    delete flusher;
    delete bgFetcher;

    delete rwUnderlying;

    /* Only couchstore has a read write store and a read only. ForestDB
     * only has a read write store. Hence delete the read only store only
     * in the case of couchstore.
     */
    if (kvConfig.getBackend().compare("couchdb") == 0) {
        delete roUnderlying;
    }

    delete[] vbuckets;
}

KVStore *KVShard::getRWUnderlying() {
    return rwUnderlying;
}

KVStore *KVShard::getROUnderlying() {
    return roUnderlying;
}

Flusher *KVShard::getFlusher() {
    return flusher;
}

BgFetcher *KVShard::getBgFetcher() {
    return bgFetcher;
}

void KVShard::notifyFlusher() {
    flusher->notifyFlushEvent();
}

RCPtr<VBucket> KVShard::getBucket(uint16_t id) const {
    if (id < maxVbuckets) {
        return vbuckets[id];
    } else {
        return NULL;
    }
}

void KVShard::setBucket(const RCPtr<VBucket> &vb) {
    vbuckets[vb->getId()].reset(vb);
}

void KVShard::resetBucket(uint16_t id) {
    vbuckets[id].reset();
}

std::vector<int> KVShard::getVBucketsSortedByState() {
    std::vector<int> rv;
    for (int state = vbucket_state_active;
         state <= vbucket_state_dead;
         ++state) {
        for (size_t i = 0; i < maxVbuckets; ++i) {
            RCPtr<VBucket> b = vbuckets[i];
            if (b && b->getState() == state) {
                rv.push_back(b->getId());
            }
        }
    }
    return rv;
}

std::vector<int> KVShard::getVBuckets() {
    std::vector<int> rv;
    for (size_t i = 0; i < maxVbuckets; ++i) {
        RCPtr<VBucket> b = vbuckets[i];
        if (b) {
            rv.push_back(b->getId());
        }
    }
    return rv;
}

bool KVShard::setHighPriorityVbSnapshotFlag(bool highPriority) {
    bool inverse = !highPriority;
    return highPrioritySnapshot.compare_exchange_strong(inverse, highPriority);
}

bool KVShard::setLowPriorityVbSnapshotFlag(bool lowPriority) {
    bool inverse = !lowPriority;
    return lowPrioritySnapshot.compare_exchange_strong(inverse,
                                                       lowPrioritySnapshot);
}

void NotifyFlusherCB::callback(uint16_t &vb) {
    if (shard->getBucket(vb)) {
        shard->notifyFlusher();
    }
}
<commit_msg>MB-15990: KVShard::setLowPriorityVbSnapshotFlag not working as expected.<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2013 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <functional>

#include "ep_engine.h"
#include "flusher.h"
#include "kvshard.h"

KVShard::KVShard(uint16_t id, EventuallyPersistentStore &store) :
    shardId(id), highPrioritySnapshot(false),
    lowPrioritySnapshot(false),
    kvConfig(store.getEPEngine().getConfiguration(), shardId),
    highPriorityCount(0)
{
    EPStats &stats = store.getEPEngine().getEpStats();
    Configuration &config = store.getEPEngine().getConfiguration();
    maxVbuckets = config.getMaxVbuckets();

    vbuckets = new RCPtr<VBucket>[maxVbuckets];

    std::string backend = kvConfig.getBackend();
    uint16_t commitInterval = 1;

    if (backend.compare("couchdb") == 0) {
        rwUnderlying = KVStoreFactory::create(kvConfig, false);
        roUnderlying = KVStoreFactory::create(kvConfig, true);
    } else if (backend.compare("forestdb") == 0) {
        rwUnderlying = KVStoreFactory::create(kvConfig);
        roUnderlying = rwUnderlying;
        commitInterval = config.getMaxVbuckets()/config.getMaxNumShards();
    }

    flusher = new Flusher(&store, this, commitInterval);
    bgFetcher = new BgFetcher(&store, this, stats);
}

KVShard::~KVShard() {
    if (flusher->state() != stopped) {
        flusher->stop(true);
        LOG(EXTENSION_LOG_WARNING, "Terminating flusher while it is in %s",
            flusher->stateName());
    }
    delete flusher;
    delete bgFetcher;

    delete rwUnderlying;

    /* Only couchstore has a read write store and a read only. ForestDB
     * only has a read write store. Hence delete the read only store only
     * in the case of couchstore.
     */
    if (kvConfig.getBackend().compare("couchdb") == 0) {
        delete roUnderlying;
    }

    delete[] vbuckets;
}

KVStore *KVShard::getRWUnderlying() {
    return rwUnderlying;
}

KVStore *KVShard::getROUnderlying() {
    return roUnderlying;
}

Flusher *KVShard::getFlusher() {
    return flusher;
}

BgFetcher *KVShard::getBgFetcher() {
    return bgFetcher;
}

void KVShard::notifyFlusher() {
    flusher->notifyFlushEvent();
}

RCPtr<VBucket> KVShard::getBucket(uint16_t id) const {
    if (id < maxVbuckets) {
        return vbuckets[id];
    } else {
        return NULL;
    }
}

void KVShard::setBucket(const RCPtr<VBucket> &vb) {
    vbuckets[vb->getId()].reset(vb);
}

void KVShard::resetBucket(uint16_t id) {
    vbuckets[id].reset();
}

std::vector<int> KVShard::getVBucketsSortedByState() {
    std::vector<int> rv;
    for (int state = vbucket_state_active;
         state <= vbucket_state_dead;
         ++state) {
        for (size_t i = 0; i < maxVbuckets; ++i) {
            RCPtr<VBucket> b = vbuckets[i];
            if (b && b->getState() == state) {
                rv.push_back(b->getId());
            }
        }
    }
    return rv;
}

std::vector<int> KVShard::getVBuckets() {
    std::vector<int> rv;
    for (size_t i = 0; i < maxVbuckets; ++i) {
        RCPtr<VBucket> b = vbuckets[i];
        if (b) {
            rv.push_back(b->getId());
        }
    }
    return rv;
}

bool KVShard::setHighPriorityVbSnapshotFlag(bool highPriority) {
    bool inverse = !highPriority;
    return highPrioritySnapshot.compare_exchange_strong(inverse, highPriority);
}

bool KVShard::setLowPriorityVbSnapshotFlag(bool lowPriority) {
    bool inverse = !lowPriority;
    return lowPrioritySnapshot.compare_exchange_strong(inverse, lowPriority);
}

void NotifyFlusherCB::callback(uint16_t &vb) {
    if (shard->getBucket(vb)) {
        shard->notifyFlusher();
    }
}
<|endoftext|>


<commit_before>#include "Gearbox.h"

#define CHECK_EMPTY if(m_hValue.IsEmpty())from(undefined)

namespace Gearbox {

    //void ValueList::push(Value that) {
    //    push(that.operator v8::Handle<v8::Value>());
    //}

    Value::~Value() {
        if(!m_hValue.IsEmpty())
            m_hValue.MakeWeak(0, weakCallback);
    }

    void Value::from(const Value &that) {
        if(that.m_hValue.IsEmpty())
            from(that.m_pValue);
        else
            from(that.m_hValue);
    }

    void Value::from(v8::Handle<v8::Value> that) {
        //INSIDE(Value::from(v8::Handle<v8::Value>));
        if(that.IsEmpty())
            from(undefined);
        else if(that->IsNumber() || that->IsUint32() || that->IsInt32() ||  that->IsUndefined() || that->IsNull() || that->IsBoolean()) {
            m_hValue.Clear();
            m_pValue.from(that);
        }
        else
            m_hValue = v8::Persistent<v8::Value>::New(that);
    }

    void Value::from(Primitive that) {
        m_hValue.Clear();
        m_pValue = that;
    }

    String Value::to(Type<String>) {
        v8::String::Utf8Value stringValue(m_hValue.IsEmpty() ? m_pValue.operator v8::Handle<v8::Value>() : m_hValue);
        return String(*stringValue /*? *stringValue : "<string conversion failed>"*/);
    }

    int64_t Value::to(Type<int64_t>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return 1;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return 0;
        }
        return m_hValue->IntegerValue();
    }

    double Value::to(Type<double>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return 1;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return 0;
        }
        return m_hValue->NumberValue();
    }

    bool Value::to(Type<bool>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return true;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return false;
        }
        return m_hValue->BooleanValue();
    }

    Value::operator v8::Handle<v8::Value>() {
        //INSIDE(Value::operator v8::Handle<v8::Value>);
        if(m_hValue.IsEmpty())
            return m_pValue;
        else
            return m_hValue;//::Local<v8::Value>::New(m_hValue);
    }

    int Value::length() {
        if(m_hValue.IsEmpty())
            return 0;
        if(m_hValue->IsArray())
            return v8::Handle<v8::Array>::Cast(m_hValue)->Length();
        if(m_hValue->IsString())
            return m_hValue->ToString()->Length();
        return 0;
    }

    void Value::weakCallback(v8::Persistent<v8::Value> that, void*) {
        if(that->IsExternal() || that->ToObject()->HasIndexedPropertiesInExternalArrayData())
            printf("TODO: need to delete user-related stuff on disposal\n");
        that.Dispose();
    }
}<commit_msg>Gearbox: Removed an unused macro.<commit_after>#include "Gearbox.h"

namespace Gearbox {

    //void ValueList::push(Value that) {
    //    push(that.operator v8::Handle<v8::Value>());
    //}

    Value::~Value() {
        if(!m_hValue.IsEmpty())
            m_hValue.MakeWeak(0, weakCallback);
    }

    void Value::from(const Value &that) {
        if(that.m_hValue.IsEmpty())
            from(that.m_pValue);
        else
            from(that.m_hValue);
    }

    void Value::from(v8::Handle<v8::Value> that) {
        //INSIDE(Value::from(v8::Handle<v8::Value>));
        if(that.IsEmpty())
            from(undefined);
        else if(that->IsNumber() || that->IsUint32() || that->IsInt32() ||  that->IsUndefined() || that->IsNull() || that->IsBoolean()) {
            m_hValue.Clear();
            m_pValue.from(that);
        }
        else
            m_hValue = v8::Persistent<v8::Value>::New(that);
    }

    void Value::from(Primitive that) {
        m_hValue.Clear();
        m_pValue = that;
    }

    String Value::to(Type<String>) {
        v8::String::Utf8Value stringValue(m_hValue.IsEmpty() ? m_pValue.operator v8::Handle<v8::Value>() : m_hValue);
        return String(*stringValue /*? *stringValue : "<string conversion failed>"*/);
    }

    int64_t Value::to(Type<int64_t>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return 1;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return 0;
        }
        return m_hValue->IntegerValue();
    }

    double Value::to(Type<double>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return 1;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return 0;
        }
        return m_hValue->NumberValue();
    }

    bool Value::to(Type<bool>) {
        if(m_hValue.IsEmpty()) {
            if(m_pValue.m_Kind == Primitive::Number)return m_pValue.m_dValue;
            else if(m_pValue.m_Kind == Primitive::True)return true;
            else if(m_pValue.m_Kind == Primitive::Integer)return m_pValue.m_iValue;
            return false;
        }
        return m_hValue->BooleanValue();
    }

    Value::operator v8::Handle<v8::Value>() {
        //INSIDE(Value::operator v8::Handle<v8::Value>);
        if(m_hValue.IsEmpty())
            return m_pValue;
        else
            return m_hValue;//::Local<v8::Value>::New(m_hValue);
    }

    int Value::length() {
        if(m_hValue.IsEmpty())
            return 0;
        if(m_hValue->IsArray())
            return v8::Handle<v8::Array>::Cast(m_hValue)->Length();
        if(m_hValue->IsString())
            return m_hValue->ToString()->Length();
        return 0;
    }

    void Value::weakCallback(v8::Persistent<v8::Value> that, void*) {
        if(that->IsExternal() || that->ToObject()->HasIndexedPropertiesInExternalArrayData())
            printf("TODO: need to delete user-related stuff on disposal\n");
        that.Dispose();
    }
}<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file KeyMap.cxx
 ** Defines a mapping between keystrokes and commands.
 **/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include "Platform.h"

#include "Scintilla.h"

#include "KeyMap.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

KeyMap::KeyMap() : kmap(0), len(0), alloc(0) {
	for (int i = 0; MapDefault[i].key; i++) {
		AssignCmdKey(MapDefault[i].key,
			MapDefault[i].modifiers,
			MapDefault[i].msg);
	}
}

KeyMap::~KeyMap() {
	Clear();
}

void KeyMap::Clear() {
	delete []kmap;
	kmap = 0;
	len = 0;
	alloc = 0;
}

void KeyMap::AssignCmdKey(int key, int modifiers, unsigned int msg) {
	if ((len+1) >= alloc) {
		KeyToCommand *ktcNew = new KeyToCommand[alloc + 5];
		if (!ktcNew)
			return;
		for (int k = 0; k < len; k++)
			ktcNew[k] = kmap[k];
		alloc += 5;
		delete []kmap;
		kmap = ktcNew;
	}
	for (int keyIndex = 0; keyIndex < len; keyIndex++) {
		if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) {
			kmap[keyIndex].msg = msg;
			return;
		}
	}
	kmap[len].key = key;
	kmap[len].modifiers = modifiers;
	kmap[len].msg = msg;
	len++;
}

unsigned int KeyMap::Find(int key, int modifiers) {
	for (int i = 0; i < len; i++) {
		if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) {
			return kmap[i].msg;
		}
	}
	return 0;
}

const KeyToCommand KeyMap::MapDefault[] = {
    {SCK_DOWN,		SCI_NORM,	SCI_LINEDOWN},
    {SCK_DOWN,		SCI_SHIFT,	SCI_LINEDOWNEXTEND},
    {SCK_DOWN,		SCI_CTRL,	SCI_LINESCROLLDOWN},
    {SCK_DOWN,		SCI_ASHIFT,	SCI_LINEDOWNRECTEXTEND},
    {SCK_UP,		SCI_NORM,	SCI_LINEUP},
    {SCK_UP,			SCI_SHIFT,	SCI_LINEUPEXTEND},
    {SCK_UP,			SCI_CTRL,	SCI_LINESCROLLUP},
    {SCK_UP,		SCI_ASHIFT,	SCI_LINEUPRECTEXTEND},
    {'[',			SCI_CTRL,		SCI_PARAUP},
    {'[',			SCI_CSHIFT,	SCI_PARAUPEXTEND},
    {']',			SCI_CTRL,		SCI_PARADOWN},
    {']',			SCI_CSHIFT,	SCI_PARADOWNEXTEND},
    {SCK_LEFT,		SCI_NORM,	SCI_CHARLEFT},
    {SCK_LEFT,		SCI_SHIFT,	SCI_CHARLEFTEXTEND},
    {SCK_LEFT,		SCI_CTRL,	SCI_WORDLEFT},
    {SCK_LEFT,		SCI_CSHIFT,	SCI_WORDLEFTEXTEND},
    {SCK_LEFT,		SCI_ASHIFT,	SCI_CHARLEFTRECTEXTEND},
    {SCK_RIGHT,		SCI_NORM,	SCI_CHARRIGHT},
    {SCK_RIGHT,		SCI_SHIFT,	SCI_CHARRIGHTEXTEND},
    {SCK_RIGHT,		SCI_CTRL,	SCI_WORDRIGHT},
    {SCK_RIGHT,		SCI_CSHIFT,	SCI_WORDRIGHTEXTEND},
    {SCK_RIGHT,		SCI_ASHIFT,	SCI_CHARRIGHTRECTEXTEND},
    {'/',		SCI_CTRL,		SCI_WORDPARTLEFT},
    {'/',		SCI_CSHIFT,	SCI_WORDPARTLEFTEXTEND},
    {'\\',		SCI_CTRL,		SCI_WORDPARTRIGHT},
    {'\\',		SCI_CSHIFT,	SCI_WORDPARTRIGHTEXTEND},
    {SCK_HOME,		SCI_NORM,	SCI_VCHOME},
    {SCK_HOME, 		SCI_SHIFT, 	SCI_VCHOMEEXTEND},
    {SCK_HOME, 		SCI_CTRL, 	SCI_DOCUMENTSTART},
    {SCK_HOME, 		SCI_CSHIFT, 	SCI_DOCUMENTSTARTEXTEND},
    {SCK_HOME, 		SCI_ALT, 	SCI_HOMEDISPLAY},
//    {SCK_HOME,		SCI_ASHIFT,	SCI_HOMEDISPLAYEXTEND},
    {SCK_HOME,		SCI_ASHIFT,	SCI_VCHOMERECTEXTEND},
    {SCK_END,	 	SCI_NORM,	SCI_LINEEND},
    {SCK_END,	 	SCI_SHIFT, 	SCI_LINEENDEXTEND},
    {SCK_END, 		SCI_CTRL, 	SCI_DOCUMENTEND},
    {SCK_END, 		SCI_CSHIFT, 	SCI_DOCUMENTENDEXTEND},
    {SCK_END, 		SCI_ALT, 	SCI_LINEENDDISPLAY},
//    {SCK_END,		SCI_ASHIFT,	SCI_LINEENDDISPLAYEXTEND},
    {SCK_END,		SCI_ASHIFT,	SCI_LINEENDRECTEXTEND},
    {SCK_PRIOR,		SCI_NORM,	SCI_PAGEUP},
    {SCK_PRIOR,		SCI_SHIFT, 	SCI_PAGEUPEXTEND},
    {SCK_PRIOR,		SCI_ASHIFT,	SCI_PAGEUPRECTEXTEND},
    {SCK_NEXT, 		SCI_NORM, 	SCI_PAGEDOWN},
    {SCK_NEXT, 		SCI_SHIFT, 	SCI_PAGEDOWNEXTEND},
    {SCK_NEXT,		SCI_ASHIFT,	SCI_PAGEDOWNRECTEXTEND},
    {SCK_DELETE, 	SCI_NORM,	SCI_CLEAR},
    {SCK_DELETE, 	SCI_SHIFT,	SCI_CUT},
    {SCK_DELETE, 	SCI_CTRL,	SCI_DELWORDRIGHT},
    {SCK_DELETE,	SCI_CSHIFT,	SCI_DELLINERIGHT},
    {SCK_INSERT, 		SCI_NORM,	SCI_EDITTOGGLEOVERTYPE},
    {SCK_INSERT, 		SCI_SHIFT,	SCI_PASTE},
    {SCK_INSERT, 		SCI_CTRL,	SCI_COPY},
    {SCK_ESCAPE,  	SCI_NORM,	SCI_CANCEL},
    {SCK_BACK,		SCI_NORM, 	SCI_DELETEBACK},
    {SCK_BACK,		SCI_SHIFT, 	SCI_DELETEBACK},
    {SCK_BACK,		SCI_CTRL, 	SCI_DELWORDLEFT},
    {SCK_BACK, 		SCI_ALT,	SCI_UNDO},
    {SCK_BACK,		SCI_CSHIFT,	SCI_DELLINELEFT},
    {'Z', 			SCI_CTRL,	SCI_UNDO},
    {'Y', 			SCI_CTRL,	SCI_REDO},
    {'X', 			SCI_CTRL,	SCI_CUT},
    {'C', 			SCI_CTRL,	SCI_COPY},
    {'V', 			SCI_CTRL,	SCI_PASTE},
    {'A', 			SCI_CTRL,	SCI_SELECTALL},
    {SCK_TAB,		SCI_NORM,	SCI_TAB},
    {SCK_TAB,		SCI_SHIFT,	SCI_BACKTAB},
    {SCK_RETURN, 	SCI_NORM,	SCI_NEWLINE},
    {SCK_RETURN, 	SCI_SHIFT,	SCI_NEWLINE},
    {SCK_ADD, 		SCI_CTRL,	SCI_ZOOMIN},
    {SCK_SUBTRACT,	SCI_CTRL,	SCI_ZOOMOUT},
    {SCK_DIVIDE,	SCI_CTRL,	SCI_SETZOOM},
    //'L', 			SCI_CTRL,		SCI_FORMFEED,
    {'L', 			SCI_CTRL,	SCI_LINECUT},
    {'L', 			SCI_CSHIFT,	SCI_LINEDELETE},
    {'T', 			SCI_CSHIFT,	SCI_LINECOPY},
    {'T', 			SCI_CTRL,	SCI_LINETRANSPOSE},
    {'D', 			SCI_CTRL,	SCI_SELECTIONDUPLICATE},
    {'U', 			SCI_CTRL,	SCI_LOWERCASE},
    {'U', 			SCI_CSHIFT,	SCI_UPPERCASE},
    {0,0,0},
};

<commit_msg>Integrate OS X key mapping into main key map.<commit_after>// Scintilla source code edit control
/** @file KeyMap.cxx
 ** Defines a mapping between keystrokes and commands.
 **/
// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include "Platform.h"

#include "Scintilla.h"

#include "KeyMap.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

KeyMap::KeyMap() : kmap(0), len(0), alloc(0) {
	for (int i = 0; MapDefault[i].key; i++) {
		AssignCmdKey(MapDefault[i].key,
			MapDefault[i].modifiers,
			MapDefault[i].msg);
	}
}

KeyMap::~KeyMap() {
	Clear();
}

void KeyMap::Clear() {
	delete []kmap;
	kmap = 0;
	len = 0;
	alloc = 0;
}

void KeyMap::AssignCmdKey(int key, int modifiers, unsigned int msg) {
	if ((len+1) >= alloc) {
		KeyToCommand *ktcNew = new KeyToCommand[alloc + 5];
		if (!ktcNew)
			return;
		for (int k = 0; k < len; k++)
			ktcNew[k] = kmap[k];
		alloc += 5;
		delete []kmap;
		kmap = ktcNew;
	}
	for (int keyIndex = 0; keyIndex < len; keyIndex++) {
		if ((key == kmap[keyIndex].key) && (modifiers == kmap[keyIndex].modifiers)) {
			kmap[keyIndex].msg = msg;
			return;
		}
	}
	kmap[len].key = key;
	kmap[len].modifiers = modifiers;
	kmap[len].msg = msg;
	len++;
}

unsigned int KeyMap::Find(int key, int modifiers) {
	for (int i = 0; i < len; i++) {
		if ((key == kmap[i].key) && (modifiers == kmap[i].modifiers)) {
			return kmap[i].msg;
		}
	}
	return 0;
}

#if PLAT_GTK_MACOSX
#define OS_X_KEYS 1
#else
#define OS_X_KEYS 0
#endif

// Define a modifier that is exactly Ctrl key on all platforms
// Most uses of Ctrl map to Cmd on OS X but some can't so use SCI_[S]CTRL_META
#if OS_X_KEYS
#define SCI_CTRL_META SCI_META
#define SCI_SCTRL_META (SCI_META | SCI_SHIFT)
#else
#define SCI_CTRL_META SCI_CTRL
#define SCI_SCTRL_META (SCI_CTRL | SCI_SHIFT)
#endif

const KeyToCommand KeyMap::MapDefault[] = {

#if OS_X_KEYS
    {SCK_DOWN,		SCI_CTRL,	SCI_DOCUMENTEND},
    {SCK_DOWN,		SCI_CSHIFT,	SCI_DOCUMENTENDEXTEND},
    {SCK_UP,		SCI_CTRL,	SCI_DOCUMENTSTART},
    {SCK_UP,		SCI_CSHIFT,	SCI_DOCUMENTSTARTEXTEND},
    {SCK_LEFT,		SCI_CTRL,	SCI_VCHOME},
    {SCK_LEFT,		SCI_CSHIFT,	SCI_VCHOMEEXTEND},
    {SCK_RIGHT,		SCI_CTRL,	SCI_LINEEND},
    {SCK_RIGHT,		SCI_CSHIFT,	SCI_LINEENDEXTEND},
#endif

    {SCK_DOWN,		SCI_NORM,	SCI_LINEDOWN},
    {SCK_DOWN,		SCI_SHIFT,	SCI_LINEDOWNEXTEND},
    {SCK_DOWN,		SCI_CTRL_META,	SCI_LINESCROLLDOWN},
    {SCK_DOWN,		SCI_ASHIFT,	SCI_LINEDOWNRECTEXTEND},
    {SCK_UP,		SCI_NORM,	SCI_LINEUP},
    {SCK_UP,			SCI_SHIFT,	SCI_LINEUPEXTEND},
    {SCK_UP,			SCI_CTRL_META,	SCI_LINESCROLLUP},
    {SCK_UP,		SCI_ASHIFT,	SCI_LINEUPRECTEXTEND},
    {'[',			SCI_CTRL,		SCI_PARAUP},
    {'[',			SCI_CSHIFT,	SCI_PARAUPEXTEND},
    {']',			SCI_CTRL,		SCI_PARADOWN},
    {']',			SCI_CSHIFT,	SCI_PARADOWNEXTEND},
    {SCK_LEFT,		SCI_NORM,	SCI_CHARLEFT},
    {SCK_LEFT,		SCI_SHIFT,	SCI_CHARLEFTEXTEND},
    {SCK_LEFT,		SCI_CTRL_META,	SCI_WORDLEFT},
    {SCK_LEFT,		SCI_SCTRL_META,	SCI_WORDLEFTEXTEND},
    {SCK_LEFT,		SCI_ASHIFT,	SCI_CHARLEFTRECTEXTEND},
    {SCK_RIGHT,		SCI_NORM,	SCI_CHARRIGHT},
    {SCK_RIGHT,		SCI_SHIFT,	SCI_CHARRIGHTEXTEND},
    {SCK_RIGHT,		SCI_CTRL_META,	SCI_WORDRIGHT},
    {SCK_RIGHT,		SCI_SCTRL_META,	SCI_WORDRIGHTEXTEND},
    {SCK_RIGHT,		SCI_ASHIFT,	SCI_CHARRIGHTRECTEXTEND},
    {'/',		SCI_CTRL,		SCI_WORDPARTLEFT},
    {'/',		SCI_CSHIFT,	SCI_WORDPARTLEFTEXTEND},
    {'\\',		SCI_CTRL,		SCI_WORDPARTRIGHT},
    {'\\',		SCI_CSHIFT,	SCI_WORDPARTRIGHTEXTEND},
    {SCK_HOME,		SCI_NORM,	SCI_VCHOME},
    {SCK_HOME, 		SCI_SHIFT, 	SCI_VCHOMEEXTEND},
    {SCK_HOME, 		SCI_CTRL, 	SCI_DOCUMENTSTART},
    {SCK_HOME, 		SCI_CSHIFT, 	SCI_DOCUMENTSTARTEXTEND},
    {SCK_HOME, 		SCI_ALT, 	SCI_HOMEDISPLAY},
    {SCK_HOME,		SCI_ASHIFT,	SCI_VCHOMERECTEXTEND},
    {SCK_END,	 	SCI_NORM,	SCI_LINEEND},
    {SCK_END,	 	SCI_SHIFT, 	SCI_LINEENDEXTEND},
    {SCK_END, 		SCI_CTRL, 	SCI_DOCUMENTEND},
    {SCK_END, 		SCI_CSHIFT, 	SCI_DOCUMENTENDEXTEND},
    {SCK_END, 		SCI_ALT, 	SCI_LINEENDDISPLAY},
    {SCK_END,		SCI_ASHIFT,	SCI_LINEENDRECTEXTEND},
    {SCK_PRIOR,		SCI_NORM,	SCI_PAGEUP},
    {SCK_PRIOR,		SCI_SHIFT, 	SCI_PAGEUPEXTEND},
    {SCK_PRIOR,		SCI_ASHIFT,	SCI_PAGEUPRECTEXTEND},
    {SCK_NEXT, 		SCI_NORM, 	SCI_PAGEDOWN},
    {SCK_NEXT, 		SCI_SHIFT, 	SCI_PAGEDOWNEXTEND},
    {SCK_NEXT,		SCI_ASHIFT,	SCI_PAGEDOWNRECTEXTEND},
    {SCK_DELETE, 	SCI_NORM,	SCI_CLEAR},
    {SCK_DELETE, 	SCI_SHIFT,	SCI_CUT},
    {SCK_DELETE, 	SCI_CTRL,	SCI_DELWORDRIGHT},
    {SCK_DELETE,	SCI_CSHIFT,	SCI_DELLINERIGHT},
    {SCK_INSERT, 		SCI_NORM,	SCI_EDITTOGGLEOVERTYPE},
    {SCK_INSERT, 		SCI_SHIFT,	SCI_PASTE},
    {SCK_INSERT, 		SCI_CTRL,	SCI_COPY},
    {SCK_ESCAPE,  	SCI_NORM,	SCI_CANCEL},
    {SCK_BACK,		SCI_NORM, 	SCI_DELETEBACK},
    {SCK_BACK,		SCI_SHIFT, 	SCI_DELETEBACK},
    {SCK_BACK,		SCI_CTRL, 	SCI_DELWORDLEFT},
    {SCK_BACK, 		SCI_ALT,	SCI_UNDO},
    {SCK_BACK,		SCI_CSHIFT,	SCI_DELLINELEFT},
    {'Z', 			SCI_CTRL,	SCI_UNDO},
#if OS_X_KEYS
    {'Z', 			SCI_CSHIFT,	SCI_REDO},
#else
    {'Y', 			SCI_CTRL,	SCI_REDO},
#endif
    {'X', 			SCI_CTRL,	SCI_CUT},
    {'C', 			SCI_CTRL,	SCI_COPY},
    {'V', 			SCI_CTRL,	SCI_PASTE},
    {'A', 			SCI_CTRL,	SCI_SELECTALL},
    {SCK_TAB,		SCI_NORM,	SCI_TAB},
    {SCK_TAB,		SCI_SHIFT,	SCI_BACKTAB},
    {SCK_RETURN, 	SCI_NORM,	SCI_NEWLINE},
    {SCK_RETURN, 	SCI_SHIFT,	SCI_NEWLINE},
    {SCK_ADD, 		SCI_CTRL,	SCI_ZOOMIN},
    {SCK_SUBTRACT,	SCI_CTRL,	SCI_ZOOMOUT},
    {SCK_DIVIDE,	SCI_CTRL,	SCI_SETZOOM},
    {'L', 			SCI_CTRL,	SCI_LINECUT},
    {'L', 			SCI_CSHIFT,	SCI_LINEDELETE},
    {'T', 			SCI_CSHIFT,	SCI_LINECOPY},
    {'T', 			SCI_CTRL,	SCI_LINETRANSPOSE},
    {'D', 			SCI_CTRL,	SCI_SELECTIONDUPLICATE},
    {'U', 			SCI_CTRL,	SCI_LOWERCASE},
    {'U', 			SCI_CSHIFT,	SCI_UPPERCASE},
    {0,0,0},
};

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.Match("\\\n")) {
				sc.Forward();
				continue;
			}
			if (sc.Match("\\\r\n")) {
				sc.Forward();
				sc.Forward();
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment &&
			(style == SCE_C_COMMENT || style == SCE_C_COMMENTDOC)) {
			if (style != stylePrev) {
				levelCurrent++;
			} else if ((style != styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<commit_msg>Fixed folding problem when keywords appeared in document comments.<commit_after>// Scintilla source code edit control
/** @file LexCPP.cxx
 ** Lexer for C++, C, Java, and Javascript.
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool IsOKBeforeRE(const int ch) {
	return (ch == '(') || (ch == '=') || (ch == ',');
}

static inline bool IsAWordChar(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}

static inline bool IsAWordStart(const int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsADoxygenChar(const int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
		    ch == '\\' || ch == '&' || ch == '<' ||
			ch == '>' || ch == '#' || ch == '{' ||
			ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsStateComment(const int state) {
	return ((state == SCE_C_COMMENT) ||
		      (state == SCE_C_COMMENTLINE) ||
		      (state == SCE_C_COMMENTDOC) ||
		      (state == SCE_C_COMMENTDOCKEYWORD) ||
		      (state == SCE_C_COMMENTDOCKEYWORDERROR));
}

static inline bool IsStateString(const int state) {
	return ((state == SCE_C_STRING) || (state == SCE_C_VERBATIM));
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

	WordList &keywords = *keywordlists[0];
	WordList &keywords2 = *keywordlists[1];
	WordList &keywords3 = *keywordlists[2];

	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor") != 0;

	// Do not leak onto next line
	if (initStyle == SCE_C_STRINGEOL)
		initStyle = SCE_C_DEFAULT;

	int chPrevNonWhite = ' ';
	int visibleChars = 0;
	bool lastWordWasUUID = false;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart && (sc.state == SCE_C_STRING)) {
			// Prevent SCE_C_STRINGEOL from leaking back to previous line
			sc.SetState(SCE_C_STRING);
		}

		// Handle line continuation generically.
		if (sc.ch == '\\') {
			if (sc.Match("\\\n")) {
				sc.Forward();
				continue;
			}
			if (sc.Match("\\\r\n")) {
				sc.Forward();
				sc.Forward();
				continue;
			}
		}

		// Determine if the current state should terminate.
		if (sc.state == SCE_C_OPERATOR) {
			sc.SetState(SCE_C_DEFAULT);
		} else if (sc.state == SCE_C_NUMBER) {
			if (!IsAWordChar(sc.ch)) {
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_IDENTIFIER) {
			if (!IsAWordChar(sc.ch) || (sc.ch == '.')) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (keywords.InList(s)) {
					lastWordWasUUID = strcmp(s, "uuid") == 0;
					sc.ChangeState(SCE_C_WORD);
				} else if (keywords2.InList(s)) {
					sc.ChangeState(SCE_C_WORD2);
				}
				sc.SetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_PREPROCESSOR) {
			if (stylingWithinPreprocessor) {
				if (IsASpace(sc.ch)) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else {
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_COMMENT) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_COMMENTDOC) {
			if (sc.Match('*', '/')) {
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '@' || sc.ch == '\\') {
				sc.SetState(SCE_C_COMMENTDOCKEYWORD);
			}
		} else if (sc.state == SCE_C_COMMENTLINE || sc.state == SCE_C_COMMENTLINEDOC) {
			if (sc.atLineEnd) {
				sc.SetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_COMMENTDOCKEYWORD) {
			if (sc.Match('*', '/')) {
				sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				sc.Forward();
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (!IsADoxygenChar(sc.ch)) {
				char s[100];
				sc.GetCurrent(s, sizeof(s));
				if (!isspace(sc.ch) || !keywords3.InList(s+1)) {
					sc.ChangeState(SCE_C_COMMENTDOCKEYWORDERROR);
				}
				sc.SetState(SCE_C_COMMENTDOC);
			}
		} else if (sc.state == SCE_C_STRING) {
			if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\"') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			}
		} else if (sc.state == SCE_C_CHARACTER) {
			if (sc.atLineEnd) {
				sc.ChangeState(SCE_C_STRINGEOL);
				sc.ForwardSetState(SCE_C_DEFAULT);
				visibleChars = 0;
			} else if (sc.ch == '\\') {
				if (sc.chNext == '\"' || sc.chNext == '\'' || sc.chNext == '\\') {
					sc.Forward();
				}
			} else if (sc.ch == '\'') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			}
		} else if (sc.state == SCE_C_REGEX) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == '/') {
				sc.ForwardSetState(SCE_C_DEFAULT);
			} else if (sc.ch == '\\') {
				// Gobble up the quoted character
				if (sc.chNext == '\\' || sc.chNext == '/') {
					sc.Forward();
				}
			}
		} else if (sc.state == SCE_C_VERBATIM) {
			if (sc.ch == '\"') {
				if (sc.chNext == '\"') {
					sc.Forward();
				} else {
					sc.ForwardSetState(SCE_C_DEFAULT);
				}
			}
		} else if (sc.state == SCE_C_UUID) {
			if (sc.ch == '\r' || sc.ch == '\n' || sc.ch == ')') {
				sc.SetState(SCE_C_DEFAULT);
			}
		}

		// Determine if a new state should be entered.
		if (sc.state == SCE_C_DEFAULT) {
			if (sc.Match('@', '\"')) {
				sc.SetState(SCE_C_VERBATIM);
				sc.Forward();
			} else if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_NUMBER);
				}
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				if (lastWordWasUUID) {
					sc.SetState(SCE_C_UUID);
					lastWordWasUUID = false;
				} else {
					sc.SetState(SCE_C_IDENTIFIER);
				}
			} else if (sc.Match('/', '*')) {
				if (sc.Match("/**") || sc.Match("/*!")) {	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTDOC);
				} else {
					sc.SetState(SCE_C_COMMENT);
				}
				sc.Forward();	// Eat the * so it isn't used for the end of the comment
			} else if (sc.Match('/', '/')) {
				if (sc.Match("///") || sc.Match("//!"))	// Support of Qt/Doxygen doc. style
					sc.SetState(SCE_C_COMMENTLINEDOC);
				else
					sc.SetState(SCE_C_COMMENTLINE);
			} else if (sc.ch == '/' && IsOKBeforeRE(chPrevNonWhite)) {
				sc.SetState(SCE_C_REGEX);
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_C_STRING);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_C_CHARACTER);
			} else if (sc.ch == '#' && visibleChars == 0) {
				// Preprocessor commands are alone on their line
				sc.SetState(SCE_C_PREPROCESSOR);
				// Skip whitespace between # and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ') && (sc.ch == '\t') && sc.More());
				if (sc.atLineEnd) {
					sc.SetState(SCE_C_DEFAULT);
				}
			} else if (isoperator(static_cast<char>(sc.ch))) {
				sc.SetState(SCE_C_OPERATOR);
			}
		}

		if (sc.atLineEnd) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			chPrevNonWhite = ' ';
			visibleChars = 0;
			lastWordWasUUID = false;
		}
		if (!IsASpace(sc.ch)) {
			chPrevNonWhite = sc.ch;
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return style == SCE_C_COMMENT ||
		style == SCE_C_COMMENTDOC ||
		style == SCE_C_COMMENTDOCKEYWORD ||
		style == SCE_C_COMMENTDOCKEYWORDERROR;
}

static void FoldCppDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelCurrent++;
			} else if (!IsStreamCommentStyle(styleNext) && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelCurrent--;
			}
		}
		if (style == SCE_C_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cppWordLists[] = {
	"Primary keywords and identifiers",
	"Secondary keywords and identifiers",
	"Documentation comment keywords",
	0,
};

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc, "cpp", FoldCppDoc, cppWordLists);
LexerModule lmTCL(SCLEX_TCL, ColouriseCppDoc, "tcl", FoldCppDoc, cppWordLists);
<|endoftext|>