<commit_before>/*
 * This file is part of the krss library
 *
 * Copyright (C) 2009 Frank Osterfeld <osterfeld@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "rssitemserializer.h"
#include "rssitem.h"
#include "category.h"
#include "enclosure.h"
#include "person.h"

#include <KDateTime>

#include <QDataStream>

using namespace KRss;

void RssItemSerializer::serialize( const RssItem& item, QByteArray& ba, ItemPart part ) {
    QDataStream stream( &ba, QIODevice::WriteOnly );
    stream << static_cast<qint64>( item.hash() )
           << item.guidIsHash()
           << item.title()
           << item.link()
           << item.description()
           << item.content()
           << item.language()
           << item.datePublished().toString()
           << item.dateUpdated().toString()
           << item.guid()
           << static_cast<qint32>( item.commentsCount() )
           << item.commentPostUri()
           << item.commentsFeed()
           << item.commentsLink();
    stream << static_cast<quint32>( item.enclosures().count() );
    Q_FOREACH( const Enclosure& i, item.enclosures() )
        stream << static_cast<qint32>( i.duration() ) << static_cast<qint32>( i.length() ) << i.title() << i.type() << i.url();
    stream << static_cast<quint32>( item.categories().count() );
    Q_FOREACH( const Category& i, item.categories() )
        stream << i.label() << i.scheme() << i.term();
    stream << static_cast<quint32>( item.authors().count() );
    Q_FOREACH( const Person& i, item.authors() )
        stream << i.email() << i.name() << i.uri();
    const QHash<QString, QString> ap = item.customProperties();
    stream << static_cast<quint32>( ap.size() );
    Q_FOREACH( const QString& key, ap.keys() )
            stream << key << ap.value( key );

}

#define READSTRING(name) QString name; stream >> name; item.set##name( name );
#define READSTRING2(name,target) QString name; stream >> name; target.set##name( name );
#define READ(type,name) type name; stream >> name; item.set##name( name );
#define READ2(type,name,target) type name; stream >> name; target.set##name( name );
#define READDATE(name) QString name; stream >> name; item.set##name( KDateTime::fromString( name ) );

bool RssItemSerializer::deserialize( RssItem& itemOut, const QByteArray& ba, ItemPart part ) {
    QDataStream stream( ba );
    RssItem item;
    READ(qint64,Hash)
    READ(bool,GuidIsHash)
    READSTRING(Title)
    READSTRING(Link)
    READSTRING(Description)
    READSTRING(Content)
    READSTRING(Language)
    READDATE(DatePublished)
    READDATE(DateUpdated)
    READSTRING(Guid)
    READ(qint32,CommentsCount)
    READSTRING(CommentPostUri)
    READSTRING(CommentsFeed)
    READSTRING(CommentsLink)
    quint32 encCount;
    stream >> encCount;
    QList<Enclosure> enclosures;
    for ( quint32 i = 0; i < encCount; ++i ) {
        Enclosure enc;
        READ2(qint32, Duration, enc)
        READ2(qint32, Length, enc)
        READSTRING2(Title, enc)
        READSTRING2(Type, enc)
        READSTRING2(Url, enc)
        enclosures.append( enc );
    }
    item.setEnclosures( enclosures );

    quint32 catCount = 0;
    stream >> catCount;
    QList<Category> categories;
    for ( quint32 i = 0; i < catCount; ++i ) {
        Category cat;
        READSTRING2(Label, cat)
        READSTRING2(Scheme, cat)
        READSTRING2(Term, cat)
        categories.append( cat );
    }
    item.setCategories( categories );

    quint32 authorCount;
    stream >> authorCount;
    QList<Person> authors;
    for ( quint32 i = 0; i < authorCount; ++i ) {
        Person auth;
        READSTRING2(Email, auth)
        READSTRING2(Name, auth)
        READSTRING2(Uri, auth)
        authors.append( auth );
    }
    item.setAuthors( authors );

    quint32 apCount;
    stream >> apCount;
    for ( quint32 i = 0; i < apCount; ++i ) {
        QString key;
        stream >> key;
        QString value;
        stream >> value;
        item.setCustomProperty( key, value );
    }

    itemOut = item;
    return true;
}

#undef READ
#undef READ2
#undef READSTRING
#undef READSTRING2
#undef READDATE
<commit_msg>respect the request payload part in the qdatastream serializer<commit_after>/*
 * This file is part of the krss library
 *
 * Copyright (C) 2009 Frank Osterfeld <osterfeld@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 *
 */

#include "rssitemserializer.h"
#include "rssitem.h"
#include "category.h"
#include "enclosure.h"
#include "person.h"

#include <KDateTime>

#include <QDataStream>

using namespace KRss;

void RssItemSerializer::serialize( const RssItem& item, QByteArray& ba, ItemPart part ) {
    QDataStream stream( &ba, QIODevice::WriteOnly );
    const bool writeHeaders = ( part & Headers ) != 0;
    const bool writeContent = ( part & Content ) != 0;

    if ( writeHeaders ) {
        stream << static_cast<qint64>( item.hash() )
               << item.guidIsHash()
               << item.title()
               << item.datePublished().toString()
               << item.dateUpdated().toString()
               << item.guid()
        stream << static_cast<quint32>( item.authors().count() );
        Q_FOREACH( const Person& i, item.authors() )
            stream << i.email() << i.name() << i.uri();
    }
    if ( writeContent ) {
        stream << item.content()
               << item.description()
               << item.link()
                << item.language()
               << static_cast<qint32>( item.commentsCount() )
               << item.commentPostUri()
               << item.commentsFeed()
               << item.commentsLink();
        stream << static_cast<quint32>( item.enclosures().count() );
        Q_FOREACH( const Enclosure& i, item.enclosures() )
            stream << static_cast<qint32>( i.duration() ) << static_cast<qint32>( i.length() ) << i.title() << i.type() << i.url();
        stream << static_cast<quint32>( item.categories().count() );
        Q_FOREACH( const Category& i, item.categories() )
            stream << i.label() << i.scheme() << i.term();
        const QHash<QString, QString> ap = item.customProperties();
        stream << static_cast<quint32>( ap.size() );
        Q_FOREACH( const QString& key, ap.keys() )
            stream << key << ap.value( key );
    }
}

#define READSTRING(name) QString name; stream >> name; item.set##name( name );
#define READSTRING2(name,target) QString name; stream >> name; target.set##name( name );
#define READ(type,name) type name; stream >> name; item.set##name( name );
#define READ2(type,name,target) type name; stream >> name; target.set##name( name );
#define READDATE(name) QString name; stream >> name; item.set##name( KDateTime::fromString( name ) );

bool RssItemSerializer::deserialize( RssItem& itemOut, const QByteArray& ba, ItemPart part ) {
    const bool readHeaders = ( part & Headers ) != 0;
    const bool readContent = ( part & Content ) != 0;

    QDataStream stream( ba );
    RssItem item;
    if ( readHeaders ) {
        READ(qint64,Hash)
        READ(bool,GuidIsHash)
        READSTRING(Title)
        READDATE(DatePublished)
        READDATE(DateUpdated)
        READSTRING(Guid)
        quint32 authorCount;
        stream >> authorCount;
        QList<Person> authors;
        for ( quint32 i = 0; i < authorCount; ++i ) {
            Person auth;
            READSTRING2(Email, auth)
            READSTRING2(Name, auth)
            READSTRING2(Uri, auth)
            authors.append( auth );
        }
        item.setAuthors( authors );
    }
    if ( readContent ) {
        READSTRING(Content)
        READSTRING(Description)
        READSTRING(Link)

        READSTRING(Language)
        READ(qint32,CommentsCount)
        READSTRING(CommentPostUri)
        READSTRING(CommentsFeed)
        READSTRING(CommentsLink)
        quint32 encCount;
        stream >> encCount;
        QList<Enclosure> enclosures;
        for ( quint32 i = 0; i < encCount; ++i ) {
            Enclosure enc;
            READ2(qint32, Duration, enc)
            READ2(qint32, Length, enc)
            READSTRING2(Title, enc)
            READSTRING2(Type, enc)
            READSTRING2(Url, enc)
            enclosures.append( enc );
        }
        item.setEnclosures( enclosures );

        quint32 catCount = 0;
        stream >> catCount;
        QList<Category> categories;
        for ( quint32 i = 0; i < catCount; ++i ) {
            Category cat;
            READSTRING2(Label, cat)
            READSTRING2(Scheme, cat)
            READSTRING2(Term, cat)
            categories.append( cat );
        }
        item.setCategories( categories );

        quint32 apCount;
        stream >> apCount;
        for ( quint32 i = 0; i < apCount; ++i ) {
            QString key;
            stream >> key;
            QString value;
            stream >> value;
            item.setCustomProperty( key, value );
        }
    }
    itemOut = item;

    if ( readHeaders )
        item.setHeadersLoaded( true );

    if ( readContent )
        item.setContentLoaded( true );

    return true;
}

#undef READ
#undef READ2
#undef READSTRING
#undef READSTRING2
#undef READDATE
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 <assert.h>
#include <dlfcn.h>  //dlopen
#include <sys/time.h>
#include <tvm/runtime/c_runtime_api.h>

#include <iostream>
#include <random>
#include <vector>

template <typename F>
auto getFunc(void* bundle, const char* name) {
  dlerror();
  auto* f = reinterpret_cast<typename std::add_pointer<F>::type>(dlsym(bundle, name));
  assert(!dlerror());
  return f;
}

static int read_all(const char* file_description, const char* file_path, char** out_params,
                    size_t* params_size) {
  FILE* fp = fopen(file_path, "rb");
  if (fp == NULL) {
    return 2;
  }

  int error = 0;
  error = fseek(fp, 0, SEEK_END);
  if (error < 0) {
    return error;
  }

  long file_size = ftell(fp);
  if (file_size < 0) {
    return (int)file_size;
  } else if (file_size == 0 || file_size > (10 << 20)) {  // file size should be in (0, 20MB].
    char buf[128];
    snprintf(buf, sizeof(buf), "determing file size: %s", file_path);
    perror(buf);
    return 2;
  }

  if (params_size != NULL) {
    *params_size = file_size;
  }

  error = fseek(fp, 0, SEEK_SET);
  if (error < 0) {
    return error;
  }

  *out_params = (char*)malloc((unsigned long)file_size);
  if (fread(*out_params, file_size, 1, fp) != 1) {
    free(*out_params);
    *out_params = NULL;

    char buf[128];
    snprintf(buf, sizeof(buf), "reading: %s", file_path);
    perror(buf);
    return 2;
  }

  error = fclose(fp);
  if (error != 0) {
    free(*out_params);
    *out_params = NULL;
  }

  return 0;
}

int main(int argc, char** argv) {
  assert(argc == 5 && "Usage: demo <bundle.so> <graph.json> <params.bin> <cat.bin>");
  auto* bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL);
  assert(bundle);

  char* json_data;
  int error = read_all("graph.json", argv[2], &json_data, NULL);
  if (error != 0) {
    return error;
  }

  char* params_data;
  size_t params_size;
  error = read_all("params.bin", argv[3], &params_data, &params_size);
  if (error != 0) {
    return error;
  }

  struct timeval t0, t1, t2, t3, t4, t5;
  gettimeofday(&t0, 0);

  auto* handle = getFunc<void*(char*, char*, int)>(bundle, "tvm_runtime_create")(
      json_data, params_data, params_size);
  gettimeofday(&t1, 0);

  float input_storage[1 * 3 * 224 * 224];
  FILE* fp = fopen(argv[3], "rb");
  fread(input_storage, 3 * 224 * 224, 4, fp);
  fclose(fp);

  std::vector<int64_t> input_shape = {1, 3, 224, 224};
  DLTensor input;
  input.data = input_storage;
  input.ctx = DLContext{kDLCPU, 0};
  input.ndim = 4;
  input.dtype = DLDataType{kDLFloat, 32, 1};
  input.shape = input_shape.data();
  input.strides = nullptr;
  input.byte_offset = 0;

  getFunc<void(void*, const char*, void*)>(bundle, "tvm_runtime_set_input")(handle, "data", &input);
  gettimeofday(&t2, 0);

  auto* ftvm_runtime_run = (auto (*)(void*)->void)dlsym(bundle, "tvm_runtime_run");
  assert(!dlerror());
  ftvm_runtime_run(handle);
  gettimeofday(&t3, 0);

  float output_storage[1000];
  std::vector<int64_t> output_shape = {1, 1000};
  DLTensor output;
  output.data = output_storage;
  output.ctx = DLContext{kDLCPU, 0};
  output.ndim = 2;
  output.dtype = DLDataType{kDLFloat, 32, 1};
  output.shape = output_shape.data();
  output.strides = nullptr;
  output.byte_offset = 0;

  getFunc<void(void*, int, void*)>(bundle, "tvm_runtime_get_output")(handle, 0, &output);
  gettimeofday(&t4, 0);

  float max_iter = -std::numeric_limits<float>::max();
  int32_t max_index = -1;
  for (auto i = 0; i < 1000; ++i) {
    if (output_storage[i] > max_iter) {
      max_iter = output_storage[i];
      max_index = i;
    }
  }

  getFunc<void(void*)>(bundle, "tvm_runtime_destroy")(handle);
  gettimeofday(&t5, 0);

  printf("The maximum position in output vector is: %d, with max-value %f.\n", max_index, max_iter);
  printf(
      "timing: %.2f ms (create), %.2f ms (set_input), %.2f ms (run), "
      "%.2f ms (get_output), %.2f ms (destroy)\n",
      (t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec - t0.tv_usec) / 1000.f,
      (t2.tv_sec - t1.tv_sec) * 1000.0f + (t2.tv_usec - t1.tv_usec) / 1000.f,
      (t3.tv_sec - t2.tv_sec) * 1000.0f + (t3.tv_usec - t2.tv_usec) / 1000.f,
      (t4.tv_sec - t3.tv_sec) * 1000.0f + (t4.tv_usec - t3.tv_usec) / 1000.f,
      (t5.tv_sec - t4.tv_sec) * 1000.0f + (t5.tv_usec - t4.tv_usec) / 1000.f);
  dlclose(bundle);

  return 0;
}
<commit_msg>[APP] Fix misprint in demo.cc during initializing of picture tensor data (#6566)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 <assert.h>
#include <dlfcn.h>  //dlopen
#include <sys/time.h>
#include <tvm/runtime/c_runtime_api.h>

#include <iostream>
#include <random>
#include <vector>

template <typename F>
auto getFunc(void* bundle, const char* name) {
  dlerror();
  auto* f = reinterpret_cast<typename std::add_pointer<F>::type>(dlsym(bundle, name));
  assert(!dlerror());
  return f;
}

static int read_all(const char* file_description, const char* file_path, char** out_params,
                    size_t* params_size) {
  FILE* fp = fopen(file_path, "rb");
  if (fp == NULL) {
    return 2;
  }

  int error = 0;
  error = fseek(fp, 0, SEEK_END);
  if (error < 0) {
    return error;
  }

  long file_size = ftell(fp);
  if (file_size < 0) {
    return (int)file_size;
  } else if (file_size == 0 || file_size > (10 << 20)) {  // file size should be in (0, 20MB].
    char buf[128];
    snprintf(buf, sizeof(buf), "determing file size: %s", file_path);
    perror(buf);
    return 2;
  }

  if (params_size != NULL) {
    *params_size = file_size;
  }

  error = fseek(fp, 0, SEEK_SET);
  if (error < 0) {
    return error;
  }

  *out_params = (char*)malloc((unsigned long)file_size);
  if (fread(*out_params, file_size, 1, fp) != 1) {
    free(*out_params);
    *out_params = NULL;

    char buf[128];
    snprintf(buf, sizeof(buf), "reading: %s", file_path);
    perror(buf);
    return 2;
  }

  error = fclose(fp);
  if (error != 0) {
    free(*out_params);
    *out_params = NULL;
  }

  return 0;
}

int main(int argc, char** argv) {
  assert(argc == 5 && "Usage: demo <bundle.so> <graph.json> <params.bin> <cat.bin>");
  auto* bundle = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL);
  assert(bundle);

  char* json_data;
  int error = read_all("graph.json", argv[2], &json_data, NULL);
  if (error != 0) {
    return error;
  }

  char* params_data;
  size_t params_size;
  error = read_all("params.bin", argv[3], &params_data, &params_size);
  if (error != 0) {
    return error;
  }

  struct timeval t0, t1, t2, t3, t4, t5;
  gettimeofday(&t0, 0);

  auto* handle = getFunc<void*(char*, char*, int)>(bundle, "tvm_runtime_create")(
      json_data, params_data, params_size);
  gettimeofday(&t1, 0);

  float input_storage[1 * 3 * 224 * 224];
  FILE* fp = fopen(argv[4], "rb");
  fread(input_storage, 3 * 224 * 224, 4, fp);
  fclose(fp);

  std::vector<int64_t> input_shape = {1, 3, 224, 224};
  DLTensor input;
  input.data = input_storage;
  input.ctx = DLContext{kDLCPU, 0};
  input.ndim = 4;
  input.dtype = DLDataType{kDLFloat, 32, 1};
  input.shape = input_shape.data();
  input.strides = nullptr;
  input.byte_offset = 0;

  getFunc<void(void*, const char*, void*)>(bundle, "tvm_runtime_set_input")(handle, "data", &input);
  gettimeofday(&t2, 0);

  auto* ftvm_runtime_run = (auto (*)(void*)->void)dlsym(bundle, "tvm_runtime_run");
  assert(!dlerror());
  ftvm_runtime_run(handle);
  gettimeofday(&t3, 0);

  float output_storage[1000];
  std::vector<int64_t> output_shape = {1, 1000};
  DLTensor output;
  output.data = output_storage;
  output.ctx = DLContext{kDLCPU, 0};
  output.ndim = 2;
  output.dtype = DLDataType{kDLFloat, 32, 1};
  output.shape = output_shape.data();
  output.strides = nullptr;
  output.byte_offset = 0;

  getFunc<void(void*, int, void*)>(bundle, "tvm_runtime_get_output")(handle, 0, &output);
  gettimeofday(&t4, 0);

  float max_iter = -std::numeric_limits<float>::max();
  int32_t max_index = -1;
  for (auto i = 0; i < 1000; ++i) {
    if (output_storage[i] > max_iter) {
      max_iter = output_storage[i];
      max_index = i;
    }
  }

  getFunc<void(void*)>(bundle, "tvm_runtime_destroy")(handle);
  gettimeofday(&t5, 0);

  printf("The maximum position in output vector is: %d, with max-value %f.\n", max_index, max_iter);
  printf(
      "timing: %.2f ms (create), %.2f ms (set_input), %.2f ms (run), "
      "%.2f ms (get_output), %.2f ms (destroy)\n",
      (t1.tv_sec - t0.tv_sec) * 1000.0f + (t1.tv_usec - t0.tv_usec) / 1000.f,
      (t2.tv_sec - t1.tv_sec) * 1000.0f + (t2.tv_usec - t1.tv_usec) / 1000.f,
      (t3.tv_sec - t2.tv_sec) * 1000.0f + (t3.tv_usec - t2.tv_usec) / 1000.f,
      (t4.tv_sec - t3.tv_sec) * 1000.0f + (t4.tv_usec - t3.tv_usec) / 1000.f,
      (t5.tv_sec - t4.tv_sec) * 1000.0f + (t5.tv_usec - t4.tv_usec) / 1000.f);
  dlclose(bundle);

  return 0;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define SYSDEF_PATH
#include "sysdef.h"
#include "csengine/sysitf.h"
#include "csws/csws.h"

class MazeEditor : public csApp
{
public:
  /// Initialize maze editor
  MazeEditor (char *AppTitle, int argc, char *argv[]) :
    csApp (AppTitle, argc, argv) {};

  ///
  virtual bool HandleEvent (csEvent &Event);

  virtual bool InitialSetup ();
};

MazeEditor *app;                        // The main Windowing System object

//-----------------------------------------------------------------------------

bool MazeEditor::InitialSetup ()
{
  if (!csApp::InitialSetup ())
    return false;

  // create a window
  csComponent *window = new csWindow (this, "-- Drag me --",
    CSWS_DEFAULTVALUE | CSWS_TOOLBAR | CSWS_CLIENTBORDER);

  csMenu *menu = (csMenu *)window->GetChild (CSWID_MENUBAR);
  if (menu)
  {
    menu->SetFont (csFontCourier);
    csMenu *submenu;

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~File", submenu);
      (void)new csMenuItem (submenu, "~Open\tCtrl+O", cscmdNothing);
      (void)new csMenuItem (submenu, "~Save\tCtrl+S", cscmdNothing);
      (void)new csMenuItem (submenu, "~Close", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Quit\tCtrl+Q", cscmdQuit);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Edit", submenu);
      (void)new csMenuItem (submenu, "~Undo\tAlt+BackSpace", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Copy\tCtrl+Ins", cscmdNothing);
      (void)new csMenuItem (submenu, "Cu~t\tShift+Del", cscmdNothing);
      (void)new csMenuItem (submenu, "~Paste\tShift+Ins", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Select all\tCtrl+/", cscmdNothing);
      (void)new csMenuItem (submenu, "~Deselect all\tCtrl+\\", cscmdNothing);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Modify", submenu);
     (void)new csMenuItem (submenu, "~Scale", cscmdNothing);
      (void)new csMenuItem (submenu, "~Rotate", cscmdNothing);
      (void)new csMenuItem (submenu, "~Move", cscmdNothing);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Test submenu", submenu);
      (void)new csMenuItem (submenu, "~One", cscmdNothing, CSMIS_DEFAULTVALUE | CSMIS_CHECKED);
      (void)new csMenuItem (submenu, "~Two", cscmdNothing);
      (void)new csMenuItem (submenu, "T~hree", cscmdNothing);
      csMenu *subsubmenu = new csMenu (NULL);
      (void)new csMenuItem (submenu, "~Four", subsubmenu);
        (void)new csMenuItem (subsubmenu, "Four / ~One", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Four / ~Two", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Four / T~hree", cscmdNothing);
      subsubmenu = new csMenu (NULL);
      (void)new csMenuItem (submenu, "Fi~ve", subsubmenu, CSMIS_NEWCOLUMN);
        (void)new csMenuItem (subsubmenu, "Five / ~One", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Five / ~Two", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Five / T~hree", cscmdNothing);
        (void)new csMenuItem (subsubmenu);
        (void)new csMenuItem (subsubmenu, "~Maximize", cscmdMaximize, CSMIS_DEFAULTVALUE | CSMIS_NOCLOSE);
        (void)new csMenuItem (subsubmenu, "~Hide", cscmdHide);
        (void)new csMenuItem (subsubmenu, "~Close", cscmdClose);
        (void)new csMenuItem (subsubmenu);
        (void)new csMenuItem (subsubmenu, "~Quit\tCtrl+Q", cscmdQuit);
        subsubmenu->GetChild (cscmdHide)->SendCommand (cscmdMenuItemCheck, (void *)true);
        subsubmenu->GetChild (cscmdQuit)->SendCommand (cscmdMenuItemCheck, (void *)true);
      (void)new csMenuItem (submenu, "~Six", cscmdNothing);
      (void)new csMenuItem (submenu, "~Seven", cscmdNothing);

    (void)new csMenuItem (menu, "~NoSubmenu");

    (void)new csMenuItem (menu, CSMIS_NEWCOLUMN);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Help", submenu);
      (void)new csMenuItem (submenu, "~Index", cscmdNothing);
      (void)new csMenuItem (submenu, "~General", cscmdNothing);
      (void)new csMenuItem (submenu, "~Context\tF1", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~About", cscmdNothing);
      submenu->GetChild (cscmdNothing)->SendCommand (cscmdDeactivateMenu, (void *)false);

    menu->PlaceItems ();
  }
  csDialog *toolbar = (csDialog *)window->GetChild (CSWID_TOOLBAR);
  if (toolbar)
  {
    csNewToolbarButton (toolbar, cscmdNothing, "hello");
    csNewToolbarButton (toolbar, cscmdNothing, "hello again");
    csNewToolbarButton (toolbar, cscmdNothing, "test");
    csNewToolbarButton (toolbar, cscmdNothing, "another test");
    csNewToolbarButton (toolbar, cscmdNothing, "yet another test");
  }
  window->SetRect (80, 20, 520, 340);

  csComponent *client = new csDialog (window);

  {
    csButton *but = new csButton (client, cscmdQuit);
    but->SetText ("~Quit!"); but->SetRect (20, 20, 90, 40);
    but->SetState (CSS_GROUP, true);
    csStatic *stat = new csStatic (client, but, "Test ~Label", csscsFrameLabel);
    stat->SetRect (10, 10, 420, 110);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE | CSBS_DEFAULT);
    but->SetText ("~Another one"); but->SetRect (50, 80, 180, 100);

    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThinRect);
    but->SetText ("hmm~..."); but->SetRect (20, 130, 100, 144);
    but->SetState (CSS_GROUP, true);
    stat = new csStatic (client, but, "Another ~Group", csscsFrameLabel);
    stat->SetRect (10, 110, 420, 270);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThickRect);
    but->SetText ("~whoops!"); but->SetRect (120, 130, 200, 144);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThinRect);
    but->SetText ("~crash!"); but->SetRect (220, 130, 300, 144);

    csInputLine *il = new csInputLine (client, 40, csifsThinRect);
    il->SetText ("input line test: check it out!"); il->SetRect (100, 200, 300, 216);
    il = new csInputLine (client, 10, csifsThickRect);
    il->SetText ("another input line"); il->SetRect (100, 220, 300, 236);
    il->SetFont (csFontCourier); il->SetSelection (0, 999);

    csListBox *lb = new csListBox (client, CSLBS_HSCROLL | CSLBS_VSCROLL, cslfsThinRect);
    lb->SetRect (320, 120, 410, 250);
    lb->SetFont (csFontCourier);
    for (int i = 1; i < 100; i++)
    {
      char tmp[20];
      sprintf (tmp, "item %d - dummy", i);
      (void)new csListBoxItem (lb, tmp, i);
    }
    lb->PlaceItems ();
  }

  window = new csWindow (this, "SetState (CSS_TOPSELECT, false)",
    CSWS_DEFAULTVALUE, cswfsThin);
  window->SetState (CSS_TOPSELECT, false);
  window->SetRect (20, 20, 400, 80);

  {
    csButton *but = new csButton (this, 9999);
    but->SetText ("Hello"); but->SetRect (10, 10, 100, 30);
    but->SetFont (csFontTiny);
    but = new csButton (this, cscmdNothing);
    but->SetText ("Othello"); but->SetRect (210, 10, 300, 30);
  }
  return true;
}

bool MazeEditor::HandleEvent (csEvent &Event)
{
  switch (Event.Type)
  {
    case csevCommand:
      switch (Event.Command.Code)
      {
        case 9999:
          {
            csWindow *d = csFileDialog (this, "test file dialog");
            if (d)
            {
              Execute (d);
              char filename [MAXPATHLEN + 1];
              csQueryFileDialog (d, filename, sizeof (filename));
              delete d;
              MessageBox (app, "Result", filename);
            }
          }
          break;
      }
      break;
  }
#if 0
  static int px, py;
  static bool draw = false;

  switch (Event.Type)
  {
    case csevMouseMove:
      if (draw)
      {
        Line (px, py, Event.Mouse.x, Event.Mouse.y, csws_Color_Gray_D);
        px = Event.Mouse.x;
        py = Event.Mouse.y;
        return Mouse->HandleEvent (Event);
      } /* endif */
      break;
    case csevMouseDown:
      if (Event.Mouse.button == 1)
      {
        draw = true;
        px = Event.Mouse.x;
        py = Event.Mouse.y;
        Line (px, py, px, py, csws_Color_White);
        return Mouse->HandleEvent (Event);
      } else if (Event.Mouse.button == 2)
      {
        static int lastcursor = 0;
        lastcursor = (lastcursor + 1) % 4;
        Mouse->SetCursor (lastcursor);
        return Mouse->HandleEvent (Event);
      } /* endif */
      break;
    case csevMouseUp:
      draw = false;
      return true;
  } /* endswitch */
#endif
  return csApp::HandleEvent (Event);
}

//---------------------------------------------------------------------------

/*
 * Main function
 */
int main (int argc, char* argv[])
{
  config = new csIniFile ("MazeD.cfg");

  app = new MazeEditor ("Crystal Space 3D maze editor", argc, argv);

  CsPrintf (MSG_INITIALIZATION, "Crystal Space Maze Editor version %s (%s).\n", VERSION, RELEASE_DATE);
  CsPrintf (MSG_INITIALIZATION, "Created by Andrew Zabolotny and others...\n\n");

  // For GUI apps double buffering is a performance hit
  System->piG2D->DoubleBuffer (false);

  if (app->InitialSetup ())
    app->Loop ();

  return (0);
}
<commit_msg>Added line drawing (left mouse button) and mouse cursor switching (right mouse button). Use to test these features in 2D drivers.<commit_after>/*
    Copyright (C) 1998 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#define SYSDEF_PATH
#include "sysdef.h"
#include "csengine/sysitf.h"
#include "csws/csws.h"

class csWsTest : public csApp
{
public:
  /// Initialize maze editor
  csWsTest (char *AppTitle, int argc, char *argv[]);

  ///
  virtual bool HandleEvent (csEvent &Event);

  virtual bool InitialSetup ();
};

csWsTest *app;                        // The main Windowing System object

//-----------------------------------------------------------------------------

// Scroll bar class default palette
static int palette_csWsTest[] =
{
  cs_Color_Gray_D,			// Application workspace
  cs_Color_Green_L,			// End points
  cs_Color_Red_L,			// lines
  cs_Color_White			// Start points
};

csWsTest::csWsTest (char *AppTitle, int argc, char *argv[]) :
  csApp (AppTitle, argc, argv)
{
  SetPalette (palette_csWsTest, sizeof (palette_csWsTest) / sizeof (int));
}

bool csWsTest::InitialSetup ()
{
  if (!csApp::InitialSetup ())
    return false;

  // create a window
  csComponent *window = new csWindow (this, "-- Drag me --",
    CSWS_DEFAULTVALUE | CSWS_TOOLBAR | CSWS_CLIENTBORDER);

  csMenu *menu = (csMenu *)window->GetChild (CSWID_MENUBAR);
  if (menu)
  {
    menu->SetFont (csFontCourier);
    csMenu *submenu;

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~File", submenu);
      (void)new csMenuItem (submenu, "~Open\tCtrl+O", cscmdNothing);
      (void)new csMenuItem (submenu, "~Save\tCtrl+S", cscmdNothing);
      (void)new csMenuItem (submenu, "~Close", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Quit\tCtrl+Q", cscmdQuit);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Edit", submenu);
      (void)new csMenuItem (submenu, "~Undo\tAlt+BackSpace", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Copy\tCtrl+Ins", cscmdNothing);
      (void)new csMenuItem (submenu, "Cu~t\tShift+Del", cscmdNothing);
      (void)new csMenuItem (submenu, "~Paste\tShift+Ins", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~Select all\tCtrl+/", cscmdNothing);
      (void)new csMenuItem (submenu, "~Deselect all\tCtrl+\\", cscmdNothing);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Modify", submenu);
     (void)new csMenuItem (submenu, "~Scale", cscmdNothing);
      (void)new csMenuItem (submenu, "~Rotate", cscmdNothing);
      (void)new csMenuItem (submenu, "~Move", cscmdNothing);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Test submenu", submenu);
      (void)new csMenuItem (submenu, "~One", cscmdNothing, CSMIS_DEFAULTVALUE | CSMIS_CHECKED);
      (void)new csMenuItem (submenu, "~Two", cscmdNothing);
      (void)new csMenuItem (submenu, "T~hree", cscmdNothing);
      csMenu *subsubmenu = new csMenu (NULL);
      (void)new csMenuItem (submenu, "~Four", subsubmenu);
        (void)new csMenuItem (subsubmenu, "Four / ~One", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Four / ~Two", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Four / T~hree", cscmdNothing);
      subsubmenu = new csMenu (NULL);
      (void)new csMenuItem (submenu, "Fi~ve", subsubmenu, CSMIS_NEWCOLUMN);
        (void)new csMenuItem (subsubmenu, "Five / ~One", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Five / ~Two", cscmdNothing);
        (void)new csMenuItem (subsubmenu, "Five / T~hree", cscmdNothing);
        (void)new csMenuItem (subsubmenu);
        (void)new csMenuItem (subsubmenu, "~Maximize", cscmdMaximize, CSMIS_DEFAULTVALUE | CSMIS_NOCLOSE);
        (void)new csMenuItem (subsubmenu, "~Hide", cscmdHide);
        (void)new csMenuItem (subsubmenu, "~Close", cscmdClose);
        (void)new csMenuItem (subsubmenu);
        (void)new csMenuItem (subsubmenu, "~Quit\tCtrl+Q", cscmdQuit);
        subsubmenu->GetChild (cscmdHide)->SendCommand (cscmdMenuItemCheck, (void *)true);
        subsubmenu->GetChild (cscmdQuit)->SendCommand (cscmdMenuItemCheck, (void *)true);
      (void)new csMenuItem (submenu, "~Six", cscmdNothing);
      (void)new csMenuItem (submenu, "~Seven", cscmdNothing);

    (void)new csMenuItem (menu, "~NoSubmenu");

    (void)new csMenuItem (menu, CSMIS_NEWCOLUMN);

    submenu = new csMenu (NULL);
    (void)new csMenuItem (menu, "~Help", submenu);
      (void)new csMenuItem (submenu, "~Index", cscmdNothing);
      (void)new csMenuItem (submenu, "~General", cscmdNothing);
      (void)new csMenuItem (submenu, "~Context\tF1", cscmdNothing);
      (void)new csMenuItem (submenu);
      (void)new csMenuItem (submenu, "~About", cscmdNothing);
      submenu->GetChild (cscmdNothing)->SendCommand (cscmdDeactivateMenu, (void *)false);

    menu->PlaceItems ();
  }
  csDialog *toolbar = (csDialog *)window->GetChild (CSWID_TOOLBAR);
  if (toolbar)
  {
    csNewToolbarButton (toolbar, cscmdNothing, "hello");
    csNewToolbarButton (toolbar, cscmdNothing, "hello again");
    csNewToolbarButton (toolbar, cscmdNothing, "test");
    csNewToolbarButton (toolbar, cscmdNothing, "another test");
    csNewToolbarButton (toolbar, cscmdNothing, "yet another test");
  }
  window->SetRect (80, 20, 520, 340);

  csComponent *client = new csDialog (window);

  {
    csButton *but = new csButton (client, cscmdQuit);
    but->SetText ("~Quit!"); but->SetRect (20, 20, 90, 40);
    but->SetState (CSS_GROUP, true);
    csStatic *stat = new csStatic (client, but, "Test ~Label", csscsFrameLabel);
    stat->SetRect (10, 10, 420, 110);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE | CSBS_DEFAULT);
    but->SetText ("~Another one"); but->SetRect (50, 80, 180, 100);

    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThinRect);
    but->SetText ("hmm~..."); but->SetRect (20, 130, 100, 144);
    but->SetState (CSS_GROUP, true);
    stat = new csStatic (client, but, "Another ~Group", csscsFrameLabel);
    stat->SetRect (10, 110, 420, 270);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThickRect);
    but->SetText ("~whoops!"); but->SetRect (120, 130, 200, 144);
    but = new csButton (client, cscmdNothing, CSBS_DEFAULTVALUE, csbfsThinRect);
    but->SetText ("~crash!"); but->SetRect (220, 130, 300, 144);

    csInputLine *il = new csInputLine (client, 40, csifsThinRect);
    il->SetText ("input line test: check it out!"); il->SetRect (100, 200, 300, 216);
    il = new csInputLine (client, 10, csifsThickRect);
    il->SetText ("another input line"); il->SetRect (100, 220, 300, 236);
    il->SetFont (csFontCourier); il->SetSelection (0, 999);

    csListBox *lb = new csListBox (client, CSLBS_HSCROLL | CSLBS_VSCROLL, cslfsThinRect);
    lb->SetRect (320, 120, 410, 250);
    lb->SetFont (csFontCourier);
    for (int i = 1; i < 100; i++)
    {
      char tmp[20];
      sprintf (tmp, "item %d - dummy", i);
      (void)new csListBoxItem (lb, tmp, i);
    }
    lb->PlaceItems ();
  }

  window = new csWindow (this, "SetState (CSS_TOPSELECT, false)",
    CSWS_DEFAULTVALUE, cswfsThin);
  window->SetState (CSS_TOPSELECT, false);
  window->SetRect (20, 20, 400, 80);

  {
    csButton *but = new csButton (this, 9999);
    but->SetText ("Hello"); but->SetRect (10, 10, 100, 30);
    but->SetFont (csFontTiny);
    but = new csButton (this, cscmdNothing);
    but->SetText ("Othello"); but->SetRect (210, 10, 300, 30);
  }
  return true;
}

bool csWsTest::HandleEvent (csEvent &Event)
{
  static csMouseCursorID mousecursors [] =
  {
    csmcNone, csmcArrow, csmcLens, csmcCross, csmcPen, csmcMove,
    csmcSizeNWSE, csmcSizeNESW, csmcSizeNS, csmcSizeEW, csmcStop, csmcWait
  };

  static int mousecursor = 1;
  static int px, py;
  static bool draw = false;

  if (csApp::HandleEvent (Event))
    return true;

  switch (Event.Type)
  {
    case csevCommand:
      switch (Event.Command.Code)
      {
        case 9999:
          {
            csWindow *d = csFileDialog (this, "test file dialog");
            if (d)
            {
              Execute (d);
              char filename [MAXPATHLEN + 1];
              csQueryFileDialog (d, filename, sizeof (filename));
              delete d;
              MessageBox (app, "Result", filename);
            }
            return true;
          }
      }
      break;

    case csevMouseMove:
      SetMouse (mousecursors [mousecursor]);
      if (draw)
      {
        // kludge: set dirty rectangle so that line won't get clipped
        csRect old (dirty);
        dirty.Set (px, py, Event.Mouse.x, Event.Mouse.y);
        dirty.Normalize ();
        dirty.xmax++; dirty.ymax++;
        Line (px, py, Event.Mouse.x, Event.Mouse.y, 2);
        dirty.Set (old);

        px = Event.Mouse.x;
        py = Event.Mouse.y;
      } /* endif */
      return true;

    case csevMouseDown:
    case csevMouseDoubleClick:
      if (Event.Mouse.Button == 1)
      {
        draw = true;
        px = Event.Mouse.x;
        py = Event.Mouse.y;

        // kludge: set dirty rectangle so that line won't get clipped
        csRect old (dirty);
        dirty.Set (px - 1, py - 1, px + 2, py + 2);
        Box (px - 1, py - 1, px + 2, py + 2, 3);
        dirty.Set (old);
      }
      else if (Event.Mouse.Button == 2)
      {
        mousecursor = (mousecursor + 1) % (sizeof (mousecursors) / sizeof (int));
        SetMouse (mousecursors [mousecursor]);
      } /* endif */
      return true;

    case csevMouseUp:
    {
      // kludge: set dirty rectangle so that line won't get clipped
      csRect old (dirty);
      dirty.Set (px - 1, py - 1, px + 2, py + 2);
      Box (px - 1, py - 1, px + 2, py + 2, 1);
      dirty.Set (old);

      draw = false;
      return true;
    }
  } /* endswitch */

  return false;
}

//---------------------------------------------------------------------------

/*
 * Main function
 */
int main (int argc, char* argv[])
{
  config = new csIniFile ("MazeD.cfg");

  app = new csWsTest ("Crystal Space 3D maze editor", argc, argv);

  CsPrintf (MSG_INITIALIZATION, "Crystal Space Windowing System test version %s (%s).\n", VERSION, RELEASE_DATE);
  CsPrintf (MSG_INITIALIZATION, "Created by Andrew Zabolotny and others...\n\n");

  // For GUI apps double buffering is a performance hit
  System->piG2D->DoubleBuffer (false);

  if (app->InitialSetup ())
    app->Loop ();

  return (0);
}
<|endoftext|>


<commit_before>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include <aliceVision/config.hpp>
#include <aliceVision/feature/PointFeature.hpp>
#include <aliceVision/feature/RegionsPerView.hpp>
#include <aliceVision/matching/IndMatch.hpp>
#include <aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp>

#include <boost/progress.hpp>

#include <vector>
#include <map>

namespace aliceVision {
namespace matchingImageCollection {

using namespace aliceVision::matching;

/**
 * @brief Perform robust model estimation (with optional guided_matching)
 * or all the pairs and regions correspondences contained in the putativeMatches set.
 * Allow to keep only geometrically coherent matches.
 * It discards pairs that do not lead to a valid robust model estimation.
 * @param[out] geometricMatches
 * @param[in] sfmData
 * @param[in] regionsPerView
 * @param[in] functor
 * @param[in] putativeMatches
 * @param[in] guidedMatching
 * @param[in] distanceRatio
 */
template<typename GeometryFunctor>
void robustModelEstimation(
  PairwiseMatches& out_geometricMatches,
  const sfm::SfMData* sfmData,
  const feature::RegionsPerView& regionsPerView,
  const GeometryFunctor& functor,
  const PairwiseMatches& putativeMatches,
  const bool guidedMatching = false,
  const double distanceRatio = 0.6)
{
  out_geometricMatches.clear();

  boost::progress_display progressBar(putativeMatches.size(), std::cout, "Robust Model Estimation\n");

#pragma omp parallel for schedule(dynamic)
  for (int i = 0; i < (int)putativeMatches.size(); ++i)
  {
    PairwiseMatches::const_iterator iter = putativeMatches.begin();
    std::advance(iter, i);

    Pair currentPair = iter->first;
    const MatchesPerDescType& putativeMatchesPerType = iter->second;
    const Pair& imagePair = iter->first;

    // apply the geometric filter (robust model estimation)
    {
      MatchesPerDescType inliers;
      GeometryFunctor geometricFilter = functor; // use a copy since we are in a multi-thread context
      const EstimationStatus state = geometricFilter.geometricEstimation(sfmData, regionsPerView, imagePair, putativeMatchesPerType, inliers);
      if(state.hasStrongSupport)
      {
        if(guidedMatching)
        {
          MatchesPerDescType guidedGeometricInliers;
          geometricFilter.Geometry_guided_matching(sfmData, regionsPerView, imagePair, distanceRatio, guidedGeometricInliers);
          //ALICEVISION_LOG_DEBUG("#before/#after: " << putative_inliers.size() << "/" << guided_geometric_inliers.size());
          std::swap(inliers, guidedGeometricInliers);
        }

#pragma omp critical
        {
          out_geometricMatches.insert(std::make_pair(currentPair, std::move(inliers)));
        }

      }
    }

#pragma omp critical
    {
      ++progressBar;
    }
  }
}

} // namespace aliceVision
} // namespace matchingImageCollection

<commit_msg>[matchingImageCollection] `GeometricFilter` fix use const<commit_after>// This file is part of the AliceVision project.
// Copyright (c) 2016 AliceVision contributors.
// Copyright (c) 2012 openMVG contributors.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include <aliceVision/config.hpp>
#include <aliceVision/feature/PointFeature.hpp>
#include <aliceVision/feature/RegionsPerView.hpp>
#include <aliceVision/matching/IndMatch.hpp>
#include <aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp>

#include <boost/progress.hpp>

#include <vector>
#include <map>

namespace aliceVision {
namespace matchingImageCollection {

using namespace aliceVision::matching;

/**
 * @brief Perform robust model estimation (with optional guided_matching)
 * or all the pairs and regions correspondences contained in the putativeMatches set.
 * Allow to keep only geometrically coherent matches.
 * It discards pairs that do not lead to a valid robust model estimation.
 * @param[out] geometricMatches
 * @param[in] sfmData
 * @param[in] regionsPerView
 * @param[in] functor
 * @param[in] putativeMatches
 * @param[in] guidedMatching
 * @param[in] distanceRatio
 */
template<typename GeometryFunctor>
void robustModelEstimation(
  PairwiseMatches& out_geometricMatches,
  const sfm::SfMData* sfmData,
  const feature::RegionsPerView& regionsPerView,
  const GeometryFunctor& functor,
  const PairwiseMatches& putativeMatches,
  const bool guidedMatching = false,
  const double distanceRatio = 0.6)
{
  out_geometricMatches.clear();

  boost::progress_display progressBar(putativeMatches.size(), std::cout, "Robust Model Estimation\n");

#pragma omp parallel for schedule(dynamic)
  for (int i = 0; i < (int)putativeMatches.size(); ++i)
  {
    PairwiseMatches::const_iterator iter = putativeMatches.begin();
    std::advance(iter, i);

    const Pair currentPair = iter->first;
    const MatchesPerDescType& putativeMatchesPerType = iter->second;
    const Pair& imagePair = iter->first;

    // apply the geometric filter (robust model estimation)
    {
      MatchesPerDescType inliers;
      GeometryFunctor geometricFilter = functor; // use a copy since we are in a multi-thread context
      const EstimationStatus state = geometricFilter.geometricEstimation(sfmData, regionsPerView, imagePair, putativeMatchesPerType, inliers);
      if(state.hasStrongSupport)
      {
        if(guidedMatching)
        {
          MatchesPerDescType guidedGeometricInliers;
          geometricFilter.Geometry_guided_matching(sfmData, regionsPerView, imagePair, distanceRatio, guidedGeometricInliers);
          //ALICEVISION_LOG_DEBUG("#before/#after: " << putative_inliers.size() << "/" << guided_geometric_inliers.size());
          std::swap(inliers, guidedGeometricInliers);
        }

#pragma omp critical
        {
          out_geometricMatches.insert(std::make_pair(currentPair, std::move(inliers)));
        }

      }
    }

#pragma omp critical
    {
      ++progressBar;
    }
  }
}

} // namespace matchingImageCollection
} // namespace aliceVision

<|endoftext|>


<commit_before>/*
 * File:  splits.cpp
 * Copyright (C) 2009 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "tr/mo/microoperations.h"
#include "tr/mo/microsurgery.h"
#include "tr/mo/blocks.h"
#include "tr/mo/nodemoutils.h"

#include "common/bit_set.h"

inline int canAcceptNodes(xptr block_xptr, int desc_size)
{
    if (block_xptr != XNULL) {
        CHECKP(block_xptr);
        node_blk_hdr * block = getBlockHeader(block_xptr);

        return (block->dsc_size >= desc_size) ? (getPageDescriptorCapacitySP(block) - block->count) : 0;
    }
    return 0;
}

inline bool tryWidenSingleBlock(xptr block_ptr, node_blk_hdr * block, int required_dsc_size)
{
    CHECKP(block_ptr);
    xptr * endpoint = (xptr *) ((char *) XADDR(block_ptr) + PAGE_SIZE) - 1;
    int total_cells = getPageDescriptorCapacitySP(block_ptr);
    int new_total_cells;
    bit_set free_cells(total_cells);
    void * indir;
    int save_indir_count;
    int i;

    free_cells.clear();

    indir = getBlockPointer(block_ptr, getBlockHeaderCP(block_ptr)->free_first_indir);

    try {
        while (indir != NULL) {
            i = endpoint - ((xptr *) indir);
            free_cells.setAt(i);

            indir = getBlockPointer(block_ptr, * (shft *) indir);
        };
    } catch (ANY_SE_EXCEPTION) {
        throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
    }

    try {
        i = total_cells - 1;
        while (i >= 0 && free_cells.testAt(i)) { i--; }
    } catch (ANY_SE_EXCEPTION) {
        throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
    }

    save_indir_count = i + 1;

    if (save_indir_count * (required_dsc_size + sizeof(xptr)) <= (PAGE_SIZE - sizeof(node_blk_hdr))) {
        shft prev;
        shft indir_count = block->indir_count;

        widenBlockDescriptor(block_ptr, required_dsc_size, save_indir_count);

        WRITEP(block_ptr);
        block->indir_count = indir_count;
        new_total_cells = getPageDescriptorCapacitySP(block_ptr);
        U_ASSERT(new_total_cells <= total_cells);
        total_cells = new_total_cells;
        U_ASSERT(total_cells >= save_indir_count);

        try {
            prev = 0;
            for (i = total_cells - 1; i >=0 ; i--) {
                if (free_cells.testAt(i)) {
                    void * iptr = endpoint - i;
                    * (shft *) iptr = prev;
                    prev = calcShift(iptr);
                }
            }
        } catch (ANY_SE_EXCEPTION) {
            throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
        }

        getBlockHeader(block_ptr)->free_first_indir = prev;

        MOCHECK(checkBlock(block_ptr));

        return true;
    }

    return false;
}

xptr widenDescriptor(xptr node_xptr, int pos, xptr set_value)
{
    xptr node_indir = getIndirectionSafeCP(node_xptr);
    node_blk_hdr * block = getBlockHeaderCP(node_xptr);
    int required_dsc_size = size_of_node(block->node_type) + (pos + 1) * sizeof(xptr);
    int node_position = 0;
    int nodes_to_move;
    xptr dest_block;
    bool widened = false;

    molog(("MOLOG (0x%llx, %d, 0x%llx)", node_xptr.to_logical_int(), pos, set_value.to_logical_int()));

    if (MAX(block->count, block->indir_count) * (required_dsc_size + sizeof(xptr)) <= (PAGE_SIZE - sizeof(node_blk_hdr))) {
        widened = tryWidenSingleBlock(block_xptr(node_xptr), block, required_dsc_size);
    }

    if (!widened) {
        for (node_base_t * node_it = getDsc((char *) xaddr(block_xptr(node_xptr)), block->desc_first);
          (void *) node_it != XADDR(node_xptr);
          node_it = getDsc((char *) xaddr(block_xptr(node_xptr)), node_it->desc_next)) {
            U_ASSERT(node_it != NULL);
            node_position++;
        }

        if (block->count - node_position < node_position + 1) {
            /* Move last nodes to the next block */
            nodes_to_move = block->count - node_position;

            dest_block = block->nblk;
            while (nodes_to_move > 0) {
                int n;

                if ((n = canAcceptNodes(dest_block, required_dsc_size)) > 0) {
                    n = MIN(n, nodes_to_move);
                    shiftManyNodesToNextBlock(block_xptr(node_xptr), n);
                    nodes_to_move -= n;
                }

                if (nodes_to_move == 0) { break; }
                CHECKP(node_xptr);
                dest_block = createBlock(XNULL, block_xptr(node_xptr));
            }
        } else {
            /* Move first nodes to the previous block */
            nodes_to_move = node_position + 1;

            dest_block = block->pblk;
            while (nodes_to_move > 0) {
                int n;

                if ((n = canAcceptNodes(dest_block, required_dsc_size)) > 0) {
                    n = MIN(n, nodes_to_move);
                    shiftManyNodesToPreviousBlock(block_xptr(node_xptr), n);
                    nodes_to_move -= n;
                }

                if (nodes_to_move == 0) { break; }
                CHECKP(node_xptr);
                dest_block = createBlock(block->snode, block->pblk);
            }
        }
    }

    node_xptr = indirectionDereferenceCP(node_indir);
    setNodeChild(node_xptr, pos, set_value);

    return node_xptr;
}

xptr splitBlock(xptr node_xptr)
{
    xptr nblk, pblk, node_indir;
    node_blk_hdr * block;
    int desc_size;
    int desc_count;

    CHECKP(node_xptr);
    node_indir = getIndirectionSafeCP(node_xptr);
    block = getBlockHeader(node_xptr);
    desc_size = block->dsc_size;
    desc_count = block->count;
    nblk = block->nblk;
    pblk = block->pblk;

    if (canAcceptNodes(pblk, desc_size) > 1) {
        shiftOneNodeToPreviousBlock(block_xptr(node_xptr));
    } else if (canAcceptNodes(nblk, desc_size) > 1) {
        shiftOneNodeToNextBlock(block_xptr(node_xptr));
    } else {
        U_ASSERT(desc_count > 3);
        createBlock(XNULL, block_xptr(node_xptr));
        shiftManyNodesToNextBlock(block_xptr(node_xptr), desc_count / 2);
    }

    return indirectionDereferenceCP(node_indir);
}
<commit_msg>Block split fix.<commit_after>/*
 * File:  splits.cpp
 * Copyright (C) 2009 The Institute for System Programming of the Russian Academy of Sciences (ISP RAS)
 */

#include "tr/mo/microoperations.h"
#include "tr/mo/microsurgery.h"
#include "tr/mo/blocks.h"
#include "tr/mo/nodemoutils.h"

#include "common/bit_set.h"

inline int canAcceptNodes(xptr block_xptr, int desc_size)
{
    if (block_xptr != XNULL) {
        CHECKP(block_xptr);
        node_blk_hdr * block = getBlockHeader(block_xptr);

        return (block->dsc_size >= desc_size) ? (getPageDescriptorCapacitySP(block) - block->count) : 0;
    }
    return 0;
}

inline bool tryWidenSingleBlock(xptr block_ptr, node_blk_hdr * block, int required_dsc_size)
{
    CHECKP(block_ptr);
    xptr * endpoint = (xptr *) ((char *) XADDR(block_ptr) + PAGE_SIZE) - 1;
    int total_cells = getPageDescriptorCapacitySP(block_ptr);
    int new_total_cells;
    bit_set free_cells(total_cells);
    void * indir;
    int save_indir_count;
    int i;

    free_cells.clear();

    indir = getBlockPointer(block_ptr, getBlockHeaderCP(block_ptr)->free_first_indir);

    try {
        while (indir != NULL) {
            i = endpoint - ((xptr *) indir);
            free_cells.setAt(i);

            indir = getBlockPointer(block_ptr, * (shft *) indir);
        };
    } catch (ANY_SE_EXCEPTION) {
        throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
    }

    try {
        i = total_cells - 1;
        while (i >= 0 && free_cells.testAt(i)) { i--; }
    } catch (ANY_SE_EXCEPTION) {
        throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
    }

    save_indir_count = i + 1;

    if (save_indir_count * (required_dsc_size + sizeof(xptr)) <= (PAGE_SIZE - sizeof(node_blk_hdr))) {
        shft prev;
        shft indir_count = block->indir_count;

        widenBlockDescriptor(block_ptr, required_dsc_size, save_indir_count);

        WRITEP(block_ptr);
        block->indir_count = indir_count;
        new_total_cells = getPageDescriptorCapacitySP(block_ptr);
        U_ASSERT(new_total_cells <= total_cells);
        total_cells = new_total_cells;
        U_ASSERT(total_cells >= save_indir_count);

        try {
            prev = 0;
            for (i = total_cells - 1; i >=0 ; i--) {
                if (free_cells.testAt(i)) {
                    void * iptr = endpoint - i;
                    * (shft *) iptr = prev;
                    prev = calcShift(iptr);
                }
            }
        } catch (ANY_SE_EXCEPTION) {
            throw SYSTEM_EXCEPTION("Exception at tryWidenSingleBlock");
        }

        getBlockHeader(block_ptr)->free_first_indir = prev;

        MOCHECK(checkBlock(block_ptr));

        return true;
    }

    return false;
}

xptr widenDescriptor(xptr node_xptr, int pos, xptr set_value)
{
    xptr node_indir = getIndirectionSafeCP(node_xptr);
    node_blk_hdr * block = getBlockHeaderCP(node_xptr);
    int required_dsc_size = size_of_node(block->node_type) + (pos + 1) * sizeof(xptr);
    int node_position = 0;
    int nodes_to_move;
    xptr dest_block;
    bool widened = false;

    molog(("MOLOG (0x%llx, %d, 0x%llx)", node_xptr.to_logical_int(), pos, set_value.to_logical_int()));

    if (MAX(block->count, block->indir_count) * (required_dsc_size + sizeof(xptr)) <= (PAGE_SIZE - sizeof(node_blk_hdr))) {
        widened = tryWidenSingleBlock(block_xptr(node_xptr), block, required_dsc_size);
    }

    if (!widened) {
        for (node_base_t * node_it = getDsc((char *) xaddr(block_xptr(node_xptr)), block->desc_first);
          (void *) node_it != XADDR(node_xptr);
          node_it = getDsc((char *) xaddr(block_xptr(node_xptr)), node_it->desc_next)) {
            U_ASSERT(node_it != NULL);
            node_position++;
        }

        if (block->count - node_position < node_position + 1) {
            /* Move last nodes to the next block */
            nodes_to_move = block->count - node_position;

            dest_block = block->nblk;
            while (nodes_to_move > 0) {
                int n;

                if ((n = canAcceptNodes(dest_block, required_dsc_size)) > 0) {
                    n = MIN(n, nodes_to_move);
                    shiftManyNodesToNextBlock(block_xptr(node_xptr), n);
                    nodes_to_move -= n;
                }

                if (nodes_to_move == 0) { break; }
                CHECKP(node_xptr);
                dest_block = createBlock(XNULL, block_xptr(node_xptr));
            }
        } else {
            /* Move first nodes to the previous block */
            nodes_to_move = node_position + 1;

            dest_block = block->pblk;
            while (nodes_to_move > 0) {
                int n;

                if ((n = canAcceptNodes(dest_block, required_dsc_size)) > 0) {
                    n = MIN(n, nodes_to_move);
                    shiftManyNodesToPreviousBlock(block_xptr(node_xptr), n);
                    nodes_to_move -= n;
                }

                if (nodes_to_move == 0) { break; }
                CHECKP(node_xptr);
                dest_block = createBlock(block->snode, block->pblk);
            }
        }
    }

    node_xptr = indirectionDereferenceCP(node_indir);
    setNodeChild(node_xptr, pos, set_value);

    return node_xptr;
}

xptr splitBlock(xptr node_xptr)
{
    xptr node_indir;
    node_blk_hdr block;

    CHECKP(node_xptr);
    node_indir = getIndirectionSafeCP(node_xptr);
    memcpy(&block, getBlockHeader(node_xptr), getHeaderSize(node_xptr));

    if (canAcceptNodes(block.pblk, block.dsc_size) > 1) {
        shiftOneNodeToPreviousBlock(block_xptr(node_xptr));
    } else if (canAcceptNodes(block.nblk, block.dsc_size) > 1) {
        shiftOneNodeToNextBlock(block_xptr(node_xptr));
    } else {
        U_ASSERT(block.count > 3);

        xptr new_block = createBlock(XNULL, block_xptr(node_xptr));
        int new_block_capacity = canAcceptNodes(new_block, block.dsc_size);
        int to_move = MIN(block.count / 2, new_block_capacity);

        U_ASSERT(to_move > 0);
        shiftManyNodesToNextBlock(block_xptr(node_xptr), to_move);
    }

    return indirectionDereferenceCP(node_indir);
}
<|endoftext|>


<commit_before>//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WorkerThread:
//   Task running thread for ANGLE, similar to a TaskRunner in Chromium.
//   Might be implemented differently depending on platform.
//

#include "libANGLE/WorkerThread.h"

#include "libANGLE/trace.h"

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED) || (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
#    include <condition_variable>
#    include <future>
#    include <mutex>
#    include <queue>
#    include <thread>
#endif  // (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED) || (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)

namespace angle
{

WaitableEvent::WaitableEvent()  = default;
WaitableEvent::~WaitableEvent() = default;

void WaitableEventDone::wait() {}

bool WaitableEventDone::isReady()
{
    return true;
}

WorkerThreadPool::WorkerThreadPool()  = default;
WorkerThreadPool::~WorkerThreadPool() = default;

class SingleThreadedWaitableEvent final : public WaitableEvent
{
  public:
    SingleThreadedWaitableEvent()           = default;
    ~SingleThreadedWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;
};

void SingleThreadedWaitableEvent::wait() {}

bool SingleThreadedWaitableEvent::isReady()
{
    return true;
}

class SingleThreadedWorkerPool final : public WorkerThreadPool
{
  public:
    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;
};

// SingleThreadedWorkerPool implementation.
std::shared_ptr<WaitableEvent> SingleThreadedWorkerPool::postWorkerTask(
    std::shared_ptr<Closure> task)
{
    (*task)();
    return std::make_shared<SingleThreadedWaitableEvent>();
}

void SingleThreadedWorkerPool::setMaxThreads(size_t maxThreads) {}

bool SingleThreadedWorkerPool::isAsync()
{
    return false;
}

#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
class AsyncWaitableEvent final : public WaitableEvent
{
  public:
    AsyncWaitableEvent() : mIsPending(true) {}
    ~AsyncWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;

  private:
    friend class AsyncWorkerPool;
    void setFuture(std::future<void> &&future);

    // To block wait() when the task is still in queue to be run.
    // Also to protect the concurrent accesses from both main thread and
    // background threads to the member fields.
    std::mutex mMutex;

    bool mIsPending;
    std::condition_variable mCondition;
    std::future<void> mFuture;
};

void AsyncWaitableEvent::setFuture(std::future<void> &&future)
{
    mFuture = std::move(future);
}

void AsyncWaitableEvent::wait()
{
    ANGLE_TRACE_EVENT0("gpu.angle", "AsyncWaitableEvent::wait");
    {
        std::unique_lock<std::mutex> lock(mMutex);
        mCondition.wait(lock, [this] { return !mIsPending; });
    }

    ASSERT(mFuture.valid());
    mFuture.wait();
}

bool AsyncWaitableEvent::isReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    if (mIsPending)
    {
        return false;
    }
    ASSERT(mFuture.valid());
    return mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

class AsyncWorkerPool final : public WorkerThreadPool
{
  public:
    AsyncWorkerPool(size_t maxThreads) : mMaxThreads(maxThreads), mRunningThreads(0) {}
    ~AsyncWorkerPool() override = default;

    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;

  private:
    void checkToRunPendingTasks();

    // To protect the concurrent accesses from both main thread and background
    // threads to the member fields.
    std::mutex mMutex;

    size_t mMaxThreads;
    size_t mRunningThreads;
    std::queue<std::pair<std::shared_ptr<AsyncWaitableEvent>, std::shared_ptr<Closure>>> mTaskQueue;
};

// AsyncWorkerPool implementation.
std::shared_ptr<WaitableEvent> AsyncWorkerPool::postWorkerTask(std::shared_ptr<Closure> task)
{
    ASSERT(mMaxThreads > 0);

    auto waitable = std::make_shared<AsyncWaitableEvent>();
    {
        std::lock_guard<std::mutex> lock(mMutex);
        mTaskQueue.push(std::make_pair(waitable, task));
    }
    checkToRunPendingTasks();
    return waitable;
}

void AsyncWorkerPool::setMaxThreads(size_t maxThreads)
{
    {
        std::lock_guard<std::mutex> lock(mMutex);
        mMaxThreads = (maxThreads == 0xFFFFFFFF ? std::thread::hardware_concurrency() : maxThreads);
    }
    checkToRunPendingTasks();
}

bool AsyncWorkerPool::isAsync()
{
    return true;
}

void AsyncWorkerPool::checkToRunPendingTasks()
{
    std::lock_guard<std::mutex> lock(mMutex);
    while (mRunningThreads < mMaxThreads && !mTaskQueue.empty())
    {
        auto task = mTaskQueue.front();
        mTaskQueue.pop();
        auto waitable = task.first;
        auto closure  = task.second;

        auto future = std::async(std::launch::async, [closure, this] {
            {
                ANGLE_TRACE_EVENT0("gpu.angle", "AsyncWorkerPool::RunTask");
                (*closure)();
            }
            {
                std::lock_guard<std::mutex> lock(mMutex);
                ASSERT(mRunningThreads != 0);
                --mRunningThreads;
            }
            checkToRunPendingTasks();
        });

        ++mRunningThreads;

        {
            std::lock_guard<std::mutex> waitableLock(waitable->mMutex);
            waitable->mIsPending = false;
            waitable->setFuture(std::move(future));
        }
        waitable->mCondition.notify_all();
    }
}
#endif  // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED)
class DelegateWaitableEvent final : public WaitableEvent
{
  public:
    DelegateWaitableEvent()           = default;
    ~DelegateWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;

    void markAsReady();

  private:
    // To protect the concurrent accesses from both main thread and background
    // threads to the member fields.
    std::mutex mMutex;

    bool mIsReady = false;
    std::condition_variable mCondition;
};

void DelegateWaitableEvent::markAsReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    mIsReady = true;
    mCondition.notify_all();
}

void DelegateWaitableEvent::wait()
{
    std::unique_lock<std::mutex> lock(mMutex);
    mCondition.wait(lock, [this] { return mIsReady; });
}

bool DelegateWaitableEvent::isReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    return mIsReady;
}

class DelegateWorkerPool final : public WorkerThreadPool
{
  public:
    DelegateWorkerPool()           = default;
    ~DelegateWorkerPool() override = default;

    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;

    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;
};

// A function wrapper to execute the closure and to notify the waitable
// event after the execution.
class DelegateWorkerTask
{
  public:
    DelegateWorkerTask(std::shared_ptr<Closure> task,
                       std::shared_ptr<DelegateWaitableEvent> waitable)
        : mTask(task), mWaitable(waitable)
    {}
    DelegateWorkerTask()                     = delete;
    DelegateWorkerTask(DelegateWorkerTask &) = delete;

    static void RunTask(void *userData)
    {
        DelegateWorkerTask *workerTask = static_cast<DelegateWorkerTask *>(userData);
        (*workerTask->mTask)();
        workerTask->mWaitable->markAsReady();

        // Delete the task after its execution.
        delete workerTask;
    }

  private:
    ~DelegateWorkerTask() = default;

    std::shared_ptr<Closure> mTask;
    std::shared_ptr<DelegateWaitableEvent> mWaitable;
};

std::shared_ptr<WaitableEvent> DelegateWorkerPool::postWorkerTask(std::shared_ptr<Closure> task)
{
    auto waitable = std::make_shared<DelegateWaitableEvent>();

    // The task will be deleted bu RunTask(...) its execution.
    DelegateWorkerTask *workerTask = new DelegateWorkerTask(task, waitable);
    auto *platform                 = ANGLEPlatformCurrent();
    platform->postWorkerTask(platform, DelegateWorkerTask::RunTask, workerTask);

    return waitable;
}

void DelegateWorkerPool::setMaxThreads(size_t maxThreads) {}

bool DelegateWorkerPool::isAsync()
{
    return true;
}
#endif

// static
std::shared_ptr<WorkerThreadPool> WorkerThreadPool::Create(bool multithreaded)
{
    std::shared_ptr<WorkerThreadPool> pool(nullptr);

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED)
    const bool hasPostWorkerTaskImpl = ANGLEPlatformCurrent()->postWorkerTask;
    if (hasPostWorkerTaskImpl && multithreaded)
    {
        pool = std::shared_ptr<WorkerThreadPool>(new DelegateWorkerPool());
    }
#endif
#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
    if (!pool && multithreaded)
    {
        pool = std::shared_ptr<WorkerThreadPool>(
            new AsyncWorkerPool(std::thread::hardware_concurrency()));
    }
#endif
    if (!pool)
    {
        return std::shared_ptr<WorkerThreadPool>(new SingleThreadedWorkerPool());
    }
    return pool;
}

// static
std::shared_ptr<WaitableEvent> WorkerThreadPool::PostWorkerTask(
    std::shared_ptr<WorkerThreadPool> pool,
    std::shared_ptr<Closure> task)
{
    std::shared_ptr<WaitableEvent> event = pool->postWorkerTask(task);
    if (event.get())
    {
        event->setWorkerThreadPool(pool);
    }
    return event;
}

}  // namespace angle
<commit_msg>Fix typos in comment<commit_after>//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// WorkerThread:
//   Task running thread for ANGLE, similar to a TaskRunner in Chromium.
//   Might be implemented differently depending on platform.
//

#include "libANGLE/WorkerThread.h"

#include "libANGLE/trace.h"

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED) || (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
#    include <condition_variable>
#    include <future>
#    include <mutex>
#    include <queue>
#    include <thread>
#endif  // (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED) || (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)

namespace angle
{

WaitableEvent::WaitableEvent()  = default;
WaitableEvent::~WaitableEvent() = default;

void WaitableEventDone::wait() {}

bool WaitableEventDone::isReady()
{
    return true;
}

WorkerThreadPool::WorkerThreadPool()  = default;
WorkerThreadPool::~WorkerThreadPool() = default;

class SingleThreadedWaitableEvent final : public WaitableEvent
{
  public:
    SingleThreadedWaitableEvent()           = default;
    ~SingleThreadedWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;
};

void SingleThreadedWaitableEvent::wait() {}

bool SingleThreadedWaitableEvent::isReady()
{
    return true;
}

class SingleThreadedWorkerPool final : public WorkerThreadPool
{
  public:
    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;
};

// SingleThreadedWorkerPool implementation.
std::shared_ptr<WaitableEvent> SingleThreadedWorkerPool::postWorkerTask(
    std::shared_ptr<Closure> task)
{
    (*task)();
    return std::make_shared<SingleThreadedWaitableEvent>();
}

void SingleThreadedWorkerPool::setMaxThreads(size_t maxThreads) {}

bool SingleThreadedWorkerPool::isAsync()
{
    return false;
}

#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
class AsyncWaitableEvent final : public WaitableEvent
{
  public:
    AsyncWaitableEvent() : mIsPending(true) {}
    ~AsyncWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;

  private:
    friend class AsyncWorkerPool;
    void setFuture(std::future<void> &&future);

    // To block wait() when the task is still in queue to be run.
    // Also to protect the concurrent accesses from both main thread and
    // background threads to the member fields.
    std::mutex mMutex;

    bool mIsPending;
    std::condition_variable mCondition;
    std::future<void> mFuture;
};

void AsyncWaitableEvent::setFuture(std::future<void> &&future)
{
    mFuture = std::move(future);
}

void AsyncWaitableEvent::wait()
{
    ANGLE_TRACE_EVENT0("gpu.angle", "AsyncWaitableEvent::wait");
    {
        std::unique_lock<std::mutex> lock(mMutex);
        mCondition.wait(lock, [this] { return !mIsPending; });
    }

    ASSERT(mFuture.valid());
    mFuture.wait();
}

bool AsyncWaitableEvent::isReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    if (mIsPending)
    {
        return false;
    }
    ASSERT(mFuture.valid());
    return mFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}

class AsyncWorkerPool final : public WorkerThreadPool
{
  public:
    AsyncWorkerPool(size_t maxThreads) : mMaxThreads(maxThreads), mRunningThreads(0) {}
    ~AsyncWorkerPool() override = default;

    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;
    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;

  private:
    void checkToRunPendingTasks();

    // To protect the concurrent accesses from both main thread and background
    // threads to the member fields.
    std::mutex mMutex;

    size_t mMaxThreads;
    size_t mRunningThreads;
    std::queue<std::pair<std::shared_ptr<AsyncWaitableEvent>, std::shared_ptr<Closure>>> mTaskQueue;
};

// AsyncWorkerPool implementation.
std::shared_ptr<WaitableEvent> AsyncWorkerPool::postWorkerTask(std::shared_ptr<Closure> task)
{
    ASSERT(mMaxThreads > 0);

    auto waitable = std::make_shared<AsyncWaitableEvent>();
    {
        std::lock_guard<std::mutex> lock(mMutex);
        mTaskQueue.push(std::make_pair(waitable, task));
    }
    checkToRunPendingTasks();
    return waitable;
}

void AsyncWorkerPool::setMaxThreads(size_t maxThreads)
{
    {
        std::lock_guard<std::mutex> lock(mMutex);
        mMaxThreads = (maxThreads == 0xFFFFFFFF ? std::thread::hardware_concurrency() : maxThreads);
    }
    checkToRunPendingTasks();
}

bool AsyncWorkerPool::isAsync()
{
    return true;
}

void AsyncWorkerPool::checkToRunPendingTasks()
{
    std::lock_guard<std::mutex> lock(mMutex);
    while (mRunningThreads < mMaxThreads && !mTaskQueue.empty())
    {
        auto task = mTaskQueue.front();
        mTaskQueue.pop();
        auto waitable = task.first;
        auto closure  = task.second;

        auto future = std::async(std::launch::async, [closure, this] {
            {
                ANGLE_TRACE_EVENT0("gpu.angle", "AsyncWorkerPool::RunTask");
                (*closure)();
            }
            {
                std::lock_guard<std::mutex> lock(mMutex);
                ASSERT(mRunningThreads != 0);
                --mRunningThreads;
            }
            checkToRunPendingTasks();
        });

        ++mRunningThreads;

        {
            std::lock_guard<std::mutex> waitableLock(waitable->mMutex);
            waitable->mIsPending = false;
            waitable->setFuture(std::move(future));
        }
        waitable->mCondition.notify_all();
    }
}
#endif  // (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED)
class DelegateWaitableEvent final : public WaitableEvent
{
  public:
    DelegateWaitableEvent()           = default;
    ~DelegateWaitableEvent() override = default;

    void wait() override;
    bool isReady() override;

    void markAsReady();

  private:
    // To protect the concurrent accesses from both main thread and background
    // threads to the member fields.
    std::mutex mMutex;

    bool mIsReady = false;
    std::condition_variable mCondition;
};

void DelegateWaitableEvent::markAsReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    mIsReady = true;
    mCondition.notify_all();
}

void DelegateWaitableEvent::wait()
{
    std::unique_lock<std::mutex> lock(mMutex);
    mCondition.wait(lock, [this] { return mIsReady; });
}

bool DelegateWaitableEvent::isReady()
{
    std::lock_guard<std::mutex> lock(mMutex);
    return mIsReady;
}

class DelegateWorkerPool final : public WorkerThreadPool
{
  public:
    DelegateWorkerPool()           = default;
    ~DelegateWorkerPool() override = default;

    std::shared_ptr<WaitableEvent> postWorkerTask(std::shared_ptr<Closure> task) override;

    void setMaxThreads(size_t maxThreads) override;
    bool isAsync() override;
};

// A function wrapper to execute the closure and to notify the waitable
// event after the execution.
class DelegateWorkerTask
{
  public:
    DelegateWorkerTask(std::shared_ptr<Closure> task,
                       std::shared_ptr<DelegateWaitableEvent> waitable)
        : mTask(task), mWaitable(waitable)
    {}
    DelegateWorkerTask()                     = delete;
    DelegateWorkerTask(DelegateWorkerTask &) = delete;

    static void RunTask(void *userData)
    {
        DelegateWorkerTask *workerTask = static_cast<DelegateWorkerTask *>(userData);
        (*workerTask->mTask)();
        workerTask->mWaitable->markAsReady();

        // Delete the task after its execution.
        delete workerTask;
    }

  private:
    ~DelegateWorkerTask() = default;

    std::shared_ptr<Closure> mTask;
    std::shared_ptr<DelegateWaitableEvent> mWaitable;
};

std::shared_ptr<WaitableEvent> DelegateWorkerPool::postWorkerTask(std::shared_ptr<Closure> task)
{
    auto waitable = std::make_shared<DelegateWaitableEvent>();

    // The task will be deleted by DelegateWorkerTask::RunTask(...) after its execution.
    DelegateWorkerTask *workerTask = new DelegateWorkerTask(task, waitable);
    auto *platform                 = ANGLEPlatformCurrent();
    platform->postWorkerTask(platform, DelegateWorkerTask::RunTask, workerTask);

    return waitable;
}

void DelegateWorkerPool::setMaxThreads(size_t maxThreads) {}

bool DelegateWorkerPool::isAsync()
{
    return true;
}
#endif

// static
std::shared_ptr<WorkerThreadPool> WorkerThreadPool::Create(bool multithreaded)
{
    std::shared_ptr<WorkerThreadPool> pool(nullptr);

#if (ANGLE_DELEGATE_WORKERS == ANGLE_ENABLED)
    const bool hasPostWorkerTaskImpl = ANGLEPlatformCurrent()->postWorkerTask;
    if (hasPostWorkerTaskImpl && multithreaded)
    {
        pool = std::shared_ptr<WorkerThreadPool>(new DelegateWorkerPool());
    }
#endif
#if (ANGLE_STD_ASYNC_WORKERS == ANGLE_ENABLED)
    if (!pool && multithreaded)
    {
        pool = std::shared_ptr<WorkerThreadPool>(
            new AsyncWorkerPool(std::thread::hardware_concurrency()));
    }
#endif
    if (!pool)
    {
        return std::shared_ptr<WorkerThreadPool>(new SingleThreadedWorkerPool());
    }
    return pool;
}

// static
std::shared_ptr<WaitableEvent> WorkerThreadPool::PostWorkerTask(
    std::shared_ptr<WorkerThreadPool> pool,
    std::shared_ptr<Closure> task)
{
    std::shared_ptr<WaitableEvent> event = pool->postWorkerTask(task);
    if (event.get())
    {
        event->setWorkerThreadPool(pool);
    }
    return event;
}

}  // namespace angle
<|endoftext|>