<commit_before>/*
 *
 * Copyright 2017 gRPC 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 <stdlib.h>
#include <string.h>

#include <grpc/grpc.h>
#include <gtest/gtest.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/surface/channel.h"

#include "test/core/util/test_config.h"

#include <stdlib.h>
#include <string.h>

namespace grpc_core {
namespace channelz {
namespace testing {

TEST(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
  ChannelNode* channelz_channel = nullptr;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if "
                        "reserved according to "
                        "https://github.com/grpc/proposal/blob/master/"
                        "A14-channelz.md";
  ChannelzRegistry::UnregisterChannelNode(uuid);
}

TEST(ChannelzRegistryTest, UuidsAreIncreasing) {
  ChannelNode* channelz_channel = nullptr;
  std::vector<intptr_t> uuids;
  uuids.reserve(10);
  for (int i = 0; i < 10; ++i) {
    // reregister the same object. It's ok since we are just testing uuids
    uuids.push_back(ChannelzRegistry::RegisterChannelNode(channelz_channel));
  }
  for (size_t i = 1; i < uuids.size(); ++i) {
    EXPECT_LT(uuids[i - 1], uuids[i]) << "Uuids must always be increasing";
  }
}

TEST(ChannelzRegistryTest, RegisterGetTest) {
  ChannelNode* channelz_channel = nullptr;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
  EXPECT_EQ(channelz_channel, retrieved);
}

TEST(ChannelzRegistryTest, RegisterManyItems) {
  ChannelNode* channelz_channel = nullptr;
  for (int i = 0; i < 100; i++) {
    intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
    ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
    EXPECT_EQ(channelz_channel, retrieved);
  }
}

TEST(ChannelzRegistryTest, NullIfNotPresentTest) {
  ChannelNode* channelz_channel = nullptr;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  // try to pull out a uuid that does not exist.
  ChannelNode* nonexistant = ChannelzRegistry::GetChannelNode(uuid + 1);
  EXPECT_EQ(nonexistant, nullptr);
  ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
  EXPECT_EQ(channelz_channel, retrieved);
}

}  // namespace testing
}  // namespace channelz
}  // namespace grpc_core

int main(int argc, char** argv) {
  grpc_test_init(argc, argv);
  grpc_init();
  ::testing::InitGoogleTest(&argc, argv);
  int ret = RUN_ALL_TESTS();
  grpc_shutdown();
  return ret;
}
<commit_msg>Use intptr_ts for channel registry test<commit_after>/*
 *
 * Copyright 2017 gRPC 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 <stdlib.h>
#include <string.h>

#include <grpc/grpc.h>
#include <gtest/gtest.h>

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include "src/core/lib/channel/channel_trace.h"
#include "src/core/lib/channel/channelz.h"
#include "src/core/lib/channel/channelz_registry.h"
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/surface/channel.h"

#include "test/core/util/test_config.h"

#include <stdlib.h>
#include <string.h>

namespace grpc_core {
namespace channelz {
namespace testing {

TEST(ChannelzRegistryTest, UuidStartsAboveZeroTest) {
  ChannelNode* channelz_channel = nullptr;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  EXPECT_GT(uuid, 0) << "First uuid chose must be greater than zero. Zero if "
                        "reserved according to "
                        "https://github.com/grpc/proposal/blob/master/"
                        "A14-channelz.md";
  ChannelzRegistry::UnregisterChannelNode(uuid);
}

TEST(ChannelzRegistryTest, UuidsAreIncreasing) {
  ChannelNode* channelz_channel = nullptr;
  std::vector<intptr_t> uuids;
  uuids.reserve(10);
  for (int i = 0; i < 10; ++i) {
    // reregister the same object. It's ok since we are just testing uuids
    uuids.push_back(ChannelzRegistry::RegisterChannelNode(channelz_channel));
  }
  for (size_t i = 1; i < uuids.size(); ++i) {
    EXPECT_LT(uuids[i - 1], uuids[i]) << "Uuids must always be increasing";
  }
}

TEST(ChannelzRegistryTest, RegisterGetTest) {
  // we hackily jam an intptr_t into this pointer to check for equality later
  ChannelNode* channelz_channel = (ChannelNode*)42;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
  EXPECT_EQ(channelz_channel, retrieved);
}

TEST(ChannelzRegistryTest, RegisterManyItems) {
  // we hackily jam an intptr_t into this pointer to check for equality later
  ChannelNode* channelz_channel = (ChannelNode*)42;
  for (int i = 0; i < 100; i++) {
    intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
    ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
    EXPECT_EQ(channelz_channel, retrieved);
  }
}

TEST(ChannelzRegistryTest, NullIfNotPresentTest) {
  // we hackily jam an intptr_t into this pointer to check for equality later
  ChannelNode* channelz_channel = (ChannelNode*)42;
  intptr_t uuid = ChannelzRegistry::RegisterChannelNode(channelz_channel);
  // try to pull out a uuid that does not exist.
  ChannelNode* nonexistant = ChannelzRegistry::GetChannelNode(uuid + 1);
  EXPECT_EQ(nonexistant, nullptr);
  ChannelNode* retrieved = ChannelzRegistry::GetChannelNode(uuid);
  EXPECT_EQ(channelz_channel, retrieved);
}

}  // namespace testing
}  // namespace channelz
}  // namespace grpc_core

int main(int argc, char** argv) {
  grpc_test_init(argc, argv);
  grpc_init();
  ::testing::InitGoogleTest(&argc, argv);
  int ret = RUN_ALL_TESTS();
  grpc_shutdown();
  return ret;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                               HttpHandler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

HttpHandler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(HttpHandler::HANDLER_DONE);
  }

  char* filename = nullptr;
  std::string errorMessage;
  long systemError;

  if (TRI_GetTempName("uploads", &filename, false, systemError, errorMessage) != TRI_ERROR_NO_ERROR) {
    errorMessage = "could not generate temp file: " + errorMessage;
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, errorMessage);
    return status_t(HttpHandler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);

  if (found) {
    bool multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(HttpHandler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(HttpHandler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &json);
  TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, &json, "filename", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, fullName, strlen(fullName)));
  TRI_Free(TRI_CORE_MEM_ZONE, fullName);

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);

  // success
  return status_t(HttpHandler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>The UploadHandler now uses VelocyPack instead of TRI_json_t<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                               HttpHandler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

HttpHandler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(HttpHandler::HANDLER_DONE);
  }

  char* filename = nullptr;
  std::string errorMessage;
  long systemError;

  if (TRI_GetTempName("uploads", &filename, false, systemError, errorMessage) != TRI_ERROR_NO_ERROR) {
    errorMessage = "could not generate temp file: " + errorMessage;
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, errorMessage);
    return status_t(HttpHandler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);

  if (found) {
    bool multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(HttpHandler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(HttpHandler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  VPackBuilder b;
  b.add(VPackValue(VPackValueType::Object));
  b.add("filename", VPackValue(fullName));
  TRI_Free(TRI_CORE_MEM_ZONE, fullName);

  b.close();
  VPackSlice s = b.slice();

  generateResult(HttpResponse::CREATED, s);
  // success
  return status_t(HttpHandler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before>// Halide tutorial lesson 20: Cloning Funcs

// This lesson demonstrates how to use Func::clone_in to create a clone of
// a Func.

// On linux, you can compile and run it like so:
// g++ lesson_20*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_20 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_20

// On os x:
// g++ lesson_20*.cpp -g -I ../include -L ../bin -lHalide -o lesson_20 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_20

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_20_cloning_funcs
// in a shell at the top of the halide source tree.

// The only Halide header file you need is Halide.h. It includes all of Halide.
#include "Halide.h"

// We'll also include stdio for printf.
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    // First we'll declare some Vars to use below.
    Var x("x"), y("y"), xo("xo"), yo("yo"), xi("xi"), yi("yi");

    // This lesson will be about cloning a Func using the Func::clone_in
    // directive
    {
        // Consider a simple two-stage pipeline:
        Func f("f_single"), g("g_single"), h("h_single");
        f(x, y) = x + y;
        g(x, y) = 2 * f(x, y) + 3;
        h(x, y) = f(x, y) + g(x, y) + 10;

        f.compute_root();
        g.compute_root();
        h.compute_root();

        // This produces the following loop nests:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f(x, y) + 3
        // for y:
        //   for x:
        //     h(x, y) = f(x, y) + g(x, y) + 10

        // Using Func::clone, we can replace calls to 'f' inside 'g' with
        // clone of 'f' using the schedule alone:
        Func f_clone_in_g = f.clone_in(g);
        f_clone_in_g.compute_root();

        // Equivalently, we could also chain the schedules like so:
        // f.clone_in(g).compute_root();

        // This produces the following loop nests:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     f_clone_in_g(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f_clone_in_g(x, y) + 3
        // for y:
        //   for x:
        //     h(x, y) = f(x, y) + g(x, y) + 10

        h.realize(5, 5);

        // The schedule directive f.clone_in(g) replaces all calls to 'f'
        // inside 'g' with a clone of 'f' and then returns that clone.
        // Essentially, it rewrites the original pipeline above into the
        // following:
        {
            Func f_clone_in_g("f_clone_in_g"), f("f"), g("g"), h("h");
            f(x, y) = x + y;
            f_clone_in_g(x, y) = x + y;
            g(x, y) = 2 * f_clone_in_g(x, y) + 3;
            h(x, y) = f(x, y) + g(x, y) + 10;

            f.compute_root();
            f_clone_in_g.compute_root();
            g.compute_root();
            h.compute_root();
        }
    }

    {
        // In the schedule above, only the calls to 'f' made by 'g' are
        // replaced. Other calls made to 'f' would still call 'f' directly
        // (i.e. 'h' still calls 'f' and not the clone). If we wish to
        // replace all calls to 'f' made by both 'g' and 'h' with a single
        // clone, we simply say f.clone_in({g, h}).

        // Consider a three stage pipeline, with two consumers of f:
        Func f("f_group"), g("g_group"), h("h_group"), out("out_group");
        f(x, y) = x + y;
        g(x, y) = 2 * f(x, y);
        h(x, y) = f(x, y) + 10;
        out(x, y) = f(x, y) + g(x, y) + h(x, y);

        f.compute_root();
        g.compute_root();
        h.compute_root();
        out.compute_root();

        // We will replace all calls to 'f' inside both 'g' and 'h'
        // with calls to a single clone:
        f.clone_in({g, h}).compute_root();

        // The equivalent loop nests are:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     f_clone(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f_clone(x, y)
        // for y:
        //   for x:
        //     h(x, y) = f_clone(x, y) + 10
        // for y:
        //   for x:
        //     out(x, y) = f(x, y) + g(x, y) + h(x, y)

        out.realize(5, 5);
    }

    printf("Success!\n");

    return 0;
}
<commit_msg>Add more example to the clone_in tutorial<commit_after>// Halide tutorial lesson 20: Cloning Funcs

// This lesson demonstrates how to use Func::clone_in to create a clone of
// a Func.

// On linux, you can compile and run it like so:
// g++ lesson_20*.cpp -g -I ../include -L ../bin -lHalide -lpthread -ldl -o lesson_20 -std=c++11
// LD_LIBRARY_PATH=../bin ./lesson_20

// On os x:
// g++ lesson_20*.cpp -g -I ../include -L ../bin -lHalide -o lesson_20 -std=c++11
// DYLD_LIBRARY_PATH=../bin ./lesson_20

// If you have the entire Halide source tree, you can also build it by
// running:
//    make tutorial_lesson_20_cloning_funcs
// in a shell at the top of the halide source tree.

// The only Halide header file you need is Halide.h. It includes all of Halide.
#include "Halide.h"

// We'll also include stdio for printf.
#include <stdio.h>

using namespace Halide;

int main(int argc, char **argv) {
    // First we'll declare some Vars to use below.
    Var x("x"), y("y"), xo("xo"), yo("yo"), xi("xi"), yi("yi");

    // This lesson will be about cloning a Func using the Func::clone_in
    // directive
    {
        // Consider a simple two-stage pipeline:
        Func f("f_single"), g("g_single"), h("h_single");
        f(x, y) = x + y;
        g(x, y) = 2 * f(x, y) + 3;
        h(x, y) = f(x, y) + g(x, y) + 10;

        f.compute_root();
        g.compute_root();
        h.compute_root();

        // This produces the following loop nests:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f(x, y) + 3
        // for y:
        //   for x:
        //     h(x, y) = f(x, y) + g(x, y) + 10

        // Using Func::clone, we can replace calls to 'f' inside 'g' with
        // a clone of 'f' using the schedule alone:
        Func f_clone_in_g = f.clone_in(g);
        f_clone_in_g.compute_root();

        // Equivalently, we could also chain the schedules like so:
        // f.clone_in(g).compute_root();

        // This produces the following loop nests:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     f_clone_in_g(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f_clone_in_g(x, y) + 3
        // for y:
        //   for x:
        //     h(x, y) = f(x, y) + g(x, y) + 10

        h.realize(5, 5);

        // The schedule directive f.clone_in(g) replaces all calls to 'f'
        // inside 'g' with a clone of 'f' and then returns that clone.
        // Essentially, it rewrites the original pipeline above into the
        // following:
        {
            Func f_clone_in_g("f_clone_in_g"), f("f"), g("g"), h("h");
            f(x, y) = x + y;
            f_clone_in_g(x, y) = x + y;
            g(x, y) = 2 * f_clone_in_g(x, y) + 3;
            h(x, y) = f(x, y) + g(x, y) + 10;

            f.compute_root();
            f_clone_in_g.compute_root();
            g.compute_root();
            h.compute_root();
        }
    }

    {
        // In the schedule above, only the calls to 'f' made by 'g' are
        // replaced. Other calls made to 'f' would still call 'f' directly
        // (i.e. 'h' still calls 'f' and not the clone). If we wish to
        // replace all calls to 'f' made by both 'g' and 'h' with a single
        // clone, we simply say f.clone_in({g, h}).

        // Consider a three stage pipeline, with two consumers of f:
        Func f("f_group"), g("g_group"), h("h_group"), out("out_group");
        f(x, y) = x + y;
        g(x, y) = 2 * f(x, y);
        h(x, y) = f(x, y) + 10;
        out(x, y) = f(x, y) + g(x, y) + h(x, y);

        f.compute_root();
        g.compute_root();
        h.compute_root();
        out.compute_root();

        // We will replace all calls to 'f' inside both 'g' and 'h'
        // with calls to a single clone:
        f.clone_in({g, h}).compute_root();

        // The equivalent loop nests are:
        // for y:
        //   for x:
        //     f(x, y) = x + y
        // for y:
        //   for x:
        //     f_clone(x, y) = x + y
        // for y:
        //   for x:
        //     g(x, y) = 2 * f_clone(x, y)
        // for y:
        //   for x:
        //     h(x, y) = f_clone(x, y) + 10
        // for y:
        //   for x:
        //     out(x, y) = f(x, y) + g(x, y) + h(x, y)

        out.realize(5, 5);
    }

    {
        // One use case of Func::clone_in() is when two consumers of a producer
        // consume regions of the producer that are very disjoint. Consider
        // the following case for example:
        Func f("f"), g("g"), h("h");
        f(x) = x;
        g(x) = 2 * f(0);
        h(x) = f(99) + 10;

        // Let's schedule 'f' to be computed at root.
        f.compute_root();
        // Since both 'g' and 'h' consumes 'f', the region required of 'f'
        // in the x-dimension is [0, 99]. The equivalent loop nests are:
        // for x = 0 to 99
        //   f(x) = x
        // for x:
        //   g(x) = 2 * f(0)
        // for x:
        //   h(x) = f(99) + 10

        // If 'f' had been very expensive to compute, we might be beter off
        // with having two copies of 'f' for each consumer, 'g' and 'h', to
        // avoid unnecessary computations. To create separate copies of 'f'
        // for each consumer, we can do the following:
        f.clone_in(g).compute_root();

        // The equivalent loop nests are:
        // f(0) = x
        // f_clone(99) = x
        // for x:
        //   g(x) = 2 * f_clone(0)
        // for x:
        //   h(x) = f(99) + 10
    }

    printf("Success!\n");

    return 0;
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// 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 "../common/math/random_sampler.h"
#include "../common/core/differential_geometry.h"
#include "../common/tutorial/tutorial_device.h"
#include "../common/tutorial/scene_device.h"

namespace embree {

extern "C" ISPCScene* g_ispc_scene;
extern "C" bool g_changed;
extern "C" int g_instancing_mode;
extern "C" int g_num_hits;

#define MAX_HITS 16*1024

/* extended ray structure that gathers all hits along the ray */
struct RayExt
{
  RayExt ()
    : begin(0), end(0) {}

  unsigned int size() const {
    return end-begin;
  }

  unsigned int begin;
  unsigned int end;
  struct Hit
  {
    Hit() {}

    Hit (float t, unsigned int primID = 0xFFFFFFFF, unsigned int geomID = 0xFFFFFFFF)
      : t(t), primID(primID), geomID(geomID) {}

    /* lexicographical order (t,geomID,primID) */
    __forceinline friend bool operator < (Hit& a, Hit& b)
    {
      if (a.t == b.t) {
        if (a.geomID == b.geomID) return a.primID < b.primID;
        else                      return a.geomID < b.geomID;
      }
      return a.t < b.t;
    }

    __forceinline friend bool operator ==(Hit& a, Hit& b) {
      return a.t == b.t && a.primID == b.primID && a.geomID == b.geomID;
    }

    __forceinline friend bool operator <= (Hit& a, Hit& b)
    {
      if (a == b) return true;
      else return a < b;
    }

    float t;
    unsigned int primID;
    unsigned int geomID;
  };
  Hit hits[MAX_HITS];
};

struct IntersectContext
{
  RTCIntersectContext context;
  RayExt rayext;
};

/* scene data */
RTCScene g_scene = nullptr;

void device_key_pressed_handler(int key)
{
  //if (key == 110 /*n*/) g_use_smooth_normals = !g_use_smooth_normals;
  //else
  device_key_pressed_default(key);
}

RTCScene convertScene(ISPCScene* scene_in)
{
  RTCScene scene_out = ConvertScene(g_device, g_ispc_scene, RTC_BUILD_QUALITY_MEDIUM);
  rtcSetSceneFlags(scene_out, rtcGetSceneFlags(scene_out) | RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION);

  /* commit individual objects in case of instancing */
  if (g_instancing_mode != ISPC_INSTANCING_NONE)
  {
    for (unsigned int i=0; i<scene_in->numGeometries; i++) {
      ISPCGeometry* geometry = g_ispc_scene->geometries[i];
      if (geometry->type == GROUP) {
        rtcSetSceneFlags(geometry->scene, rtcGetSceneFlags(geometry->scene) | RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION);
        rtcCommitScene(geometry->scene);
      }
    }
  }

  /* commit changes to scene */
  return scene_out;
}

/* Filter callback function that gathers all hits */
void gatherAllHits(const struct RTCFilterFunctionNArguments* args)
{
  assert(*args->valid == -1);
  IntersectContext* context = (IntersectContext*) args->context;
  RayExt& rayext = context->rayext;
  RTCRay* ray = (RTCRay*) args->ray;
  RTCHit* hit = (RTCHit*) args->hit;
  assert(args->N == 1);
  args->valid[0] = 0; // ignore all hits

  if (rayext.end > MAX_HITS) return;

  /* add hit to list */
  rayext.hits[rayext.end++] = RayExt::Hit(ray->tfar,hit->primID,hit->geomID);
}

/* Filter callback function that gathers first N hits */
void gatherNHits(const struct RTCFilterFunctionNArguments* args)
{
  assert(*args->valid == -1);
  IntersectContext* context = (IntersectContext*) args->context;
  RayExt& rayext = context->rayext;
  RTCRay* ray = (RTCRay*) args->ray;
  RTCHit* hit = (RTCHit*) args->hit;
  assert(args->N == 1);
  args->valid[0] = 0; // ignore all hits

  if (rayext.end > MAX_HITS) return;

  RayExt::Hit nhit(ray->tfar,hit->primID,hit->geomID);

  if (rayext.begin > 0 && nhit <= rayext.hits[rayext.begin-1])
    return;

  for (size_t i=rayext.begin; i<rayext.end; i++)
    if (nhit < rayext.hits[i])
      std::swap(nhit,rayext.hits[i]);

  if (rayext.size() < g_num_hits)
    rayext.hits[rayext.end++] = nhit;
  else {
    ray->tfar = rayext.hits[rayext.end-1].t;
    args->valid[0] = -1; // accept hit
  }
}

/* task that renders a single screen tile */
Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera, RayStats& stats)
{
  IntersectContext context;
  rtcInitIntersectContext(&context.context);

  /* initialize ray */
  Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f, inf, 0.0f);

  if (g_num_hits == 0)
  {
    context.context.filter = gatherAllHits;
    rtcIntersect1(g_scene,&context.context,RTCRayHit_(ray));
    RayStats_addRay(stats);
    std::sort(&context.rayext.hits[context.rayext.begin],&context.rayext.hits[context.rayext.end]);
  }

  else
  {
    context.context.filter = gatherNHits;

    do {
      context.rayext.begin = context.rayext.end;

      for (size_t i=0; i<g_num_hits; i++)
        if (context.rayext.begin+i < MAX_HITS)
          context.rayext.hits[context.rayext.begin+i] = RayExt::Hit(neg_inf);

      rtcIntersect1(g_scene,&context.context,RTCRayHit_(ray));
      RayStats_addRay(stats);

    } while (context.rayext.size() != 0);

    context.rayext.begin = 0;
  }

  /* calculate random sequence based on hit geomIDs and primIDs */
  RandomSampler sampler = { 0 };
  for (size_t i=context.rayext.begin; i<context.rayext.end; i++) {
    sampler.s = MurmurHash3_mix(sampler.s, context.rayext.hits[i].geomID);
    sampler.s = MurmurHash3_mix(sampler.s, context.rayext.hits[i].primID);
  }
  sampler.s = MurmurHash3_finalize(sampler.s);

  /* map geomID/primID sequence to color */
  Vec3fa color;
  color.x = RandomSampler_getFloat(sampler);
  color.y = RandomSampler_getFloat(sampler);
  color.z = RandomSampler_getFloat(sampler);
  return color;
}

/* renders a single screen tile */
void renderTileStandard(int taskIndex,
                        int threadIndex,
                        int* pixels,
                        const unsigned int width,
                        const unsigned int height,
                        const float time,
                        const ISPCCamera& camera,
                        const int numTilesX,
                        const int numTilesY)
{
  const int t = taskIndex;
  const unsigned int tileY = t / numTilesX;
  const unsigned int tileX = t - tileY * numTilesX;
  const unsigned int x0 = tileX * TILE_SIZE_X;
  const unsigned int x1 = min(x0+TILE_SIZE_X,width);
  const unsigned int y0 = tileY * TILE_SIZE_Y;
  const unsigned int y1 = min(y0+TILE_SIZE_Y,height);

  for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
  {
    Vec3fa color = renderPixelStandard((float)x,(float)y,camera,g_stats[threadIndex]);

    /* write color to framebuffer */
    unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f));
    unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f));
    unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f));
    pixels[y*width+x] = (b << 16) + (g << 8) + r;
  }
}

/* task that renders a single screen tile */
void renderTileTask (int taskIndex, int threadIndex, int* pixels,
                         const unsigned int width,
                         const unsigned int height,
                         const float time,
                         const ISPCCamera& camera,
                         const int numTilesX,
                         const int numTilesY)
{
  renderTile(taskIndex,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
}

/* called by the C++ code for initialization */
extern "C" void device_init (char* cfg)
{
  /* set start render mode */
  renderTile = renderTileStandard;
  key_pressed_handler = device_key_pressed_handler;
}

/* called by the C++ code to render */
extern "C" void device_render (int* pixels,
                           const unsigned int width,
                           const unsigned int height,
                           const float time,
                           const ISPCCamera& camera)
{
  /* create scene */
  if (g_scene == nullptr) {
    g_scene = convertScene(g_ispc_scene);
    rtcCommitScene (g_scene);
  }

  /* render image */
  const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X;
  const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y;
  parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range<size_t>& range) {
    const int threadIndex = (int)TaskScheduler::threadIndex();
    for (size_t i=range.begin(); i<range.end(); i++)
      renderTileTask((int)i,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
  });
  //rtcDebug();
}

/* called by the C++ code for cleanup */
extern "C" void device_cleanup ()
{
  rtcReleaseScene (g_scene); g_scene = nullptr;
}

} // namespace embree
<commit_msg>allhits tutorial starts to work<commit_after>// ======================================================================== //
// Copyright 2009-2018 Intel Corporation                                    //
//                                                                          //
// 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 "../common/math/random_sampler.h"
#include "../common/core/differential_geometry.h"
#include "../common/tutorial/tutorial_device.h"
#include "../common/tutorial/scene_device.h"

namespace embree {

extern "C" ISPCScene* g_ispc_scene;
extern "C" bool g_changed;
extern "C" int g_instancing_mode;
extern "C" int g_num_hits;

#define MAX_HITS 16*1024

/* extended ray structure that gathers all hits along the ray */
struct RayExt
{
  RayExt ()
    : begin(0), end(0) {}

  unsigned int size() const {
    return end-begin;
  }

  unsigned int begin;
  unsigned int end;
  struct Hit
  {
    Hit() {}

    Hit (float t, unsigned int primID = 0xFFFFFFFF, unsigned int geomID = 0xFFFFFFFF)
      : t(t), primID(primID), geomID(geomID) {}

    /* lexicographical order (t,geomID,primID) */
    __forceinline friend bool operator < (Hit& a, Hit& b)
    {
      if (a.t == b.t) {
        if (a.geomID == b.geomID) return a.primID < b.primID;
        else                      return a.geomID < b.geomID;
      }
      return a.t < b.t;
    }

    __forceinline friend bool operator ==(Hit& a, Hit& b) {
      return a.t == b.t && a.primID == b.primID && a.geomID == b.geomID;
    }

    __forceinline friend bool operator <= (Hit& a, Hit& b)
    {
      if (a == b) return true;
      else return a < b;
    }

    friend std::ostream& operator<<(std::ostream& cout, const Hit& hit) {
      return cout << "Hit { t = " << hit.t << ", geomID = " << hit.geomID << ", primID = " << hit.primID << " }";
    }

    float t;
    unsigned int primID;
    unsigned int geomID;
  };
  Hit hits[MAX_HITS];
};

struct IntersectContext
{
  RTCIntersectContext context;
  RayExt rayext;
};

/* scene data */
RTCScene g_scene = nullptr;

void device_key_pressed_handler(int key)
{
  //if (key == 110 /*n*/) g_use_smooth_normals = !g_use_smooth_normals;
  //else
  device_key_pressed_default(key);
}

RTCScene convertScene(ISPCScene* scene_in)
{
  RTCScene scene_out = ConvertScene(g_device, g_ispc_scene, RTC_BUILD_QUALITY_MEDIUM);
  rtcSetSceneFlags(scene_out, rtcGetSceneFlags(scene_out) | RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION);

  /* commit individual objects in case of instancing */
  if (g_instancing_mode != ISPC_INSTANCING_NONE)
  {
    for (unsigned int i=0; i<scene_in->numGeometries; i++) {
      ISPCGeometry* geometry = g_ispc_scene->geometries[i];
      if (geometry->type == GROUP) {
        rtcSetSceneFlags(geometry->scene, rtcGetSceneFlags(geometry->scene) | RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION);
        rtcCommitScene(geometry->scene);
      }
    }
  }

  /* commit changes to scene */
  return scene_out;
}

/* Filter callback function that gathers all hits */
void gatherAllHits(const struct RTCFilterFunctionNArguments* args)
{
  assert(*args->valid == -1);
  IntersectContext* context = (IntersectContext*) args->context;
  RayExt& rayext = context->rayext;
  RTCRay* ray = (RTCRay*) args->ray;
  RTCHit* hit = (RTCHit*) args->hit;
  assert(args->N == 1);
  args->valid[0] = 0; // ignore all hits

  if (rayext.end > MAX_HITS) return;

  /* add hit to list */
  rayext.hits[rayext.end++] = RayExt::Hit(ray->tfar,hit->primID,hit->geomID);
}

/* Filter callback function that gathers first N hits */
void gatherNHits(const struct RTCFilterFunctionNArguments* args)
{
  assert(*args->valid == -1);
  IntersectContext* context = (IntersectContext*) args->context;
  RayExt& rayext = context->rayext;
  RTCRay* ray = (RTCRay*) args->ray;
  RTCHit* hit = (RTCHit*) args->hit;
  assert(args->N == 1);
  args->valid[0] = 0; // ignore all hits

  if (rayext.end > MAX_HITS) return;

  RayExt::Hit nhit(ray->tfar,hit->primID,hit->geomID);

  if (rayext.begin > 0 && nhit <= rayext.hits[rayext.begin-1])
    return;

  for (size_t i=rayext.begin; i<rayext.end; i++)
    if (nhit < rayext.hits[i])
      std::swap(nhit,rayext.hits[i]);

  if (rayext.size() < g_num_hits)
    rayext.hits[rayext.end++] = nhit;
  else {
    ray->tfar = rayext.hits[rayext.end-1].t;
    args->valid[0] = -1; // accept hit
  }
}

/* task that renders a single screen tile */
Vec3fa renderPixelStandard(float x, float y, const ISPCCamera& camera, RayStats& stats)
{
  IntersectContext context;
  rtcInitIntersectContext(&context.context);

  /* initialize ray */
  Ray ray(Vec3fa(camera.xfm.p), Vec3fa(normalize(x*camera.xfm.l.vx + y*camera.xfm.l.vy + camera.xfm.l.vz)), 0.0f, inf, 0.0f);

  if (g_num_hits == 0)
  {
    context.context.filter = gatherAllHits;
    rtcIntersect1(g_scene,&context.context,RTCRayHit_(ray));
    RayStats_addRay(stats);
    std::sort(&context.rayext.hits[context.rayext.begin],&context.rayext.hits[context.rayext.end]);
  }

  else
  {
    context.context.filter = gatherNHits;

    int iter = 0;
    do {

      if (context.rayext.end)
        ray.tnear() = context.rayext.hits[context.rayext.end-1].t;

      ray.tfar = inf;
      ray.geomID = RTC_INVALID_GEOMETRY_ID;
      context.rayext.begin = context.rayext.end;

      for (size_t i=0; i<g_num_hits; i++)
        if (context.rayext.begin+i < MAX_HITS)
          context.rayext.hits[context.rayext.begin+i] = RayExt::Hit(neg_inf);

      rtcIntersect1(g_scene,&context.context,RTCRayHit_(ray));
      RayStats_addRay(stats);
      iter++;

      /*PRINT(iter);
      for (size_t i=0; i<context.rayext.end; i++)
      {
        PRINT2(i,context.rayext.hits[i]);
        }*/

    } while (context.rayext.size() != 0);

    context.rayext.begin = 0;
  }

  /* calculate random sequence based on hit geomIDs and primIDs */
  RandomSampler sampler = { 0 };
  for (size_t i=context.rayext.begin; i<context.rayext.end; i++) {
    sampler.s = MurmurHash3_mix(sampler.s, context.rayext.hits[i].geomID);
    sampler.s = MurmurHash3_mix(sampler.s, context.rayext.hits[i].primID);
  }
  sampler.s = MurmurHash3_finalize(sampler.s);

  /* map geomID/primID sequence to color */
  Vec3fa color;
  color.x = RandomSampler_getFloat(sampler);
  color.y = RandomSampler_getFloat(sampler);
  color.z = RandomSampler_getFloat(sampler);
  return color;
}

/* renders a single screen tile */
void renderTileStandard(int taskIndex,
                        int threadIndex,
                        int* pixels,
                        const unsigned int width,
                        const unsigned int height,
                        const float time,
                        const ISPCCamera& camera,
                        const int numTilesX,
                        const int numTilesY)
{
  const int t = taskIndex;
  const unsigned int tileY = t / numTilesX;
  const unsigned int tileX = t - tileY * numTilesX;
  const unsigned int x0 = tileX * TILE_SIZE_X;
  const unsigned int x1 = min(x0+TILE_SIZE_X,width);
  const unsigned int y0 = tileY * TILE_SIZE_Y;
  const unsigned int y1 = min(y0+TILE_SIZE_Y,height);

  for (unsigned int y=y0; y<y1; y++) for (unsigned int x=x0; x<x1; x++)
  {
    //if (x != 256 || y != 256) continue;
    //PRINT2(x,y);
    Vec3fa color = renderPixelStandard((float)x,(float)y,camera,g_stats[threadIndex]);

    /* write color to framebuffer */
    unsigned int r = (unsigned int) (255.0f * clamp(color.x,0.0f,1.0f));
    unsigned int g = (unsigned int) (255.0f * clamp(color.y,0.0f,1.0f));
    unsigned int b = (unsigned int) (255.0f * clamp(color.z,0.0f,1.0f));
    pixels[y*width+x] = (b << 16) + (g << 8) + r;
  }
}

/* task that renders a single screen tile */
void renderTileTask (int taskIndex, int threadIndex, int* pixels,
                         const unsigned int width,
                         const unsigned int height,
                         const float time,
                         const ISPCCamera& camera,
                         const int numTilesX,
                         const int numTilesY)
{
  renderTile(taskIndex,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
}

/* called by the C++ code for initialization */
extern "C" void device_init (char* cfg)
{
  /* set start render mode */
  renderTile = renderTileStandard;
  key_pressed_handler = device_key_pressed_handler;
}

/* called by the C++ code to render */
extern "C" void device_render (int* pixels,
                           const unsigned int width,
                           const unsigned int height,
                           const float time,
                           const ISPCCamera& camera)
{
  /* create scene */
  if (g_scene == nullptr) {
    g_scene = convertScene(g_ispc_scene);
    rtcCommitScene (g_scene);
  }

  /* render image */
  const int numTilesX = (width +TILE_SIZE_X-1)/TILE_SIZE_X;
  const int numTilesY = (height+TILE_SIZE_Y-1)/TILE_SIZE_Y;
  parallel_for(size_t(0),size_t(numTilesX*numTilesY),[&](const range<size_t>& range) {
    const int threadIndex = (int)TaskScheduler::threadIndex();
    for (size_t i=range.begin(); i<range.end(); i++)
      renderTileTask((int)i,threadIndex,pixels,width,height,time,camera,numTilesX,numTilesY);
  });
  //rtcDebug();
}

/* called by the C++ code for cleanup */
extern "C" void device_cleanup ()
{
  rtcReleaseScene (g_scene); g_scene = nullptr;
}

} // namespace embree
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <typeinfo>
#include <stdexcept>
#include <cstdlib>
#include <ctype.h>

#define PRINT_LINE (std::cout << "line: " << __LINE__ << std::endl)

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_INTEGER,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }

  std::string str() {
    std::stringstream ss;
    ss << "Token(" << type << ", " << value << ")";
    return ss.str();
  }
};

namespace Lisp {
  class Expression;
}

// memory allocated exprs
std::list<Lisp::Expression*> objects;

namespace Lisp {
  class Expression {
  public:
    Expression() {
      objects.push_back(this);
    }
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  class Integer : public Expression {
  public:
    unsigned long value;

    Integer(std::string &avalue)  : value(std::atol(avalue.c_str())) {}
    Integer(unsigned long avalue) : value(avalue) {}

    std::string lisp_str() { return std::to_string(value); }
  };

  class Symbol : public Expression {
  public:
    std::string value;

    Symbol(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return value; }
  };

  class List : public Expression {
  public:
    std::vector<Expression*> values;

    List(std::vector<Expression*> &avalues) : values(avalues) {}

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(";
      for(Expression* value : values) {
        ss << value->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };

  class T : public Expression {
  public:
    T() {}

    std::string lisp_str() { return "T"; }
  };

  class Parser {
  public:
    std::vector<Expression*> parse(const std::string &code) {
      tokens = tokenize(code);

      if(false) { // NOTE: for debug
        for(auto tok : tokens) {
          std::cout << tok->str() << std::endl;
        }
      }

      std::vector<Expression*> exprs;
      while(!tokens.empty()) {
        exprs.push_back(parse_expr());
      }
      return exprs;
    }

  private:
    std::list<Token*> tokens;

    inline Token* cur_token() {
      return tokens.empty() ? nullptr : tokens.front();
    }

    void consume_token() {
      auto ctoken = cur_token();
      if(ctoken) delete ctoken;

      if(!tokens.empty()) tokens.pop_front();
    }

    Expression* parse_list() {
      consume_token();
      if(cur_token()->type != TOKEN_SYMBOL) {
        //TODO: raise an error
      }

      std::vector<Expression*> values;
      while(!tokens.empty() && cur_token()->type != TOKEN_BRACKET_CLOSE) {
        values.push_back(parse_expr());
      }

      return new List(values);
    }

    Expression* parse_expr() {
      Expression* ret;
      switch(cur_token()->type) {
        case TOKEN_BRACKET_OPEN:
          ret = parse_list();
          break;
        case TOKEN_STRING:
          ret = new String(cur_token()->value);
          break;
        case TOKEN_NIL:
          ret = new Nil();
          break;
        case TOKEN_SYMBOL:
          ret = new Symbol(cur_token()->value);
          break;
        case TOKEN_INTEGER:
          ret = new Integer(cur_token()->value);
          break;
        default:
          throw std::logic_error("unknown token: " + std::to_string(cur_token()->type));
      }
      consume_token();
      return ret;
    }

    bool is_symbol(char c) {
      return c == '!' || ('#' <= c && c <= '\'') || ('*' <= c && c <= '/') || isalpha(c);
    }

    bool is_number(char c) {
      return isdigit(c);
    }

    std::list<Token*> tokenize(const std::string &code) {
      std::list<Token*> tokens;

      for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
        char ch = code[i];
        if(ch == '(')
          tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
        else if(ch == ')')
          tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
        else if(ch == '"') { // string
          i++;

          size_t token_len = 0;
          while(code[i + token_len] != '"') {
            token_len++;
            if(i + token_len >= code.size()) {
              //TODO: raise an error
            }
          }
          tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
          i += token_len;
        }
        else if(ch == ' ' || ch == '\n')
          ;//skip
        else if(is_number(ch)) {
          size_t token_len = 0;
          while(is_number(code[i + token_len])) {
            token_len++;
            if(i + token_len >= code.size()) {
              // TODO: raise an error
            }
          }

          std::string token_val = code.substr(i, token_len);
          tokens.push_back(new Token(TOKEN_INTEGER, token_val));

          i += token_len - 1;
        }
        else { // symbol
          size_t token_len = 0;
          while(is_symbol(code[i + token_len])) {
            token_len++;
            if(i + token_len >= code.size()) {
              //TODO: raise an error
            }
          }

          std::string token_val = code.substr(i, token_len);
          TokenType token_type;
          if(token_val == "nil")
            token_type = TOKEN_NIL;
          else
            token_type = TOKEN_SYMBOL;

          if(token_type == TOKEN_SYMBOL)
            tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
          else
            tokens.push_back(new Token(token_type));

          i += token_len - 1;
        }
      }

      return tokens;
    }
  };

  class Evaluator {
    std::map<std::string, Expression*> env;

    Expression* eval_expr(Expression* expr) {
      const std::type_info& id = typeid(*expr);
      if(id == typeid(List)) {
        auto list = (List*)expr;
        auto name = ((Symbol*)list->values[0])->value;
        if(name == "print") {
          std::cout << (evaluate(list->values[1]))->lisp_str() << std::endl;
          return new Nil();
        }
        else if(name == "setq") {
          env[regard<Symbol>(list->values[1])->value] = list->values[2];
          return new Nil();
        }
        else if(name == "atom") {
          auto val = evaluate(list->values[1]);
          if(typeid(*val) != typeid(List)) return new T();
          else return new Nil();
        }
        else if(name == "+") {
          Integer* sum = new Integer(0);
          for(size_t i = 1 ; i < list->values.size() ; i++) {
            sum->value += ((Integer*)evaluate(list->values[i]))->value;
          }
          return sum;
        }
        else if(name == "list") {
          auto args = list->values;
          for(size_t i = 1 ; i < args.size() ; i++) {
            args[i] = evaluate(args[i]);
          }
          return new List(args);
        }
      }
      else if(id == typeid(Symbol)) {
        return env[((Symbol*)expr)->value];
      }

      return expr;
    }

  public:
    Expression* evaluate(Expression* expr) {
      return eval_expr(expr);
    }

    template<typename T> T* regard(Expression* expr) {
      if(typeid(*expr) != typeid(T)) {
        throw std::logic_error("illeagl type error: expected " + std::string(typeid(T).name()) + " but " + std::string(typeid(*expr).name()));
      }
      return (T*)expr;
    }
  };
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  Lisp::Parser parser;
  auto exprs = parser.parse(code);

  Lisp::Evaluator evaluator;
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    exprs[i] = evaluator.evaluate(exprs[i]);
  }

  // fake GC
  for(auto expr : objects) {
    delete expr;
  }

  return 0;
}
<commit_msg>list関数のバグを修正<commit_after>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <list>
#include <map>
#include <typeinfo>
#include <stdexcept>
#include <cstdlib>
#include <ctype.h>

#define PRINT_LINE (std::cout << "line: " << __LINE__ << std::endl)

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_INTEGER,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }

  std::string str() {
    std::stringstream ss;
    ss << "Token(" << type << ", " << value << ")";
    return ss.str();
  }
};

namespace Lisp {
  class Expression;
}

// memory allocated exprs
std::list<Lisp::Expression*> objects;

namespace Lisp {
  class Expression {
  public:
    Expression() {
      objects.push_back(this);
    }
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  class Integer : public Expression {
  public:
    unsigned long value;

    Integer(std::string &avalue)  : value(std::atol(avalue.c_str())) {}
    Integer(unsigned long avalue) : value(avalue) {}

    std::string lisp_str() { return std::to_string(value); }
  };

  class Symbol : public Expression {
  public:
    std::string value;

    Symbol(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return value; }
  };

  class List : public Expression {
  public:
    std::vector<Expression*> values;

    List(std::vector<Expression*> &avalues) : values(avalues) {}

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(";
      for(Expression* value : values) {
        ss << value->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };

  class T : public Expression {
  public:
    T() {}

    std::string lisp_str() { return "T"; }
  };

  class Parser {
  public:
    std::vector<Expression*> parse(const std::string &code) {
      tokens = tokenize(code);

      if(false) { // NOTE: for debug
        for(auto tok : tokens) {
          std::cout << tok->str() << std::endl;
        }
      }

      std::vector<Expression*> exprs;
      while(!tokens.empty()) {
        exprs.push_back(parse_expr());
      }
      return exprs;
    }

  private:
    std::list<Token*> tokens;

    inline Token* cur_token() {
      return tokens.empty() ? nullptr : tokens.front();
    }

    void consume_token() {
      auto ctoken = cur_token();
      if(ctoken) delete ctoken;

      if(!tokens.empty()) tokens.pop_front();
    }

    Expression* parse_list() {
      consume_token();
      if(cur_token()->type != TOKEN_SYMBOL) {
        //TODO: raise an error
      }

      std::vector<Expression*> values;
      while(!tokens.empty() && cur_token()->type != TOKEN_BRACKET_CLOSE) {
        values.push_back(parse_expr());
      }

      return new List(values);
    }

    Expression* parse_expr() {
      Expression* ret;
      switch(cur_token()->type) {
        case TOKEN_BRACKET_OPEN:
          ret = parse_list();
          break;
        case TOKEN_STRING:
          ret = new String(cur_token()->value);
          break;
        case TOKEN_NIL:
          ret = new Nil();
          break;
        case TOKEN_SYMBOL:
          ret = new Symbol(cur_token()->value);
          break;
        case TOKEN_INTEGER:
          ret = new Integer(cur_token()->value);
          break;
        default:
          throw std::logic_error("unknown token: " + std::to_string(cur_token()->type));
      }
      consume_token();
      return ret;
    }

    bool is_symbol(char c) {
      return c == '!' || ('#' <= c && c <= '\'') || ('*' <= c && c <= '/') || isalpha(c);
    }

    bool is_number(char c) {
      return isdigit(c);
    }

    std::list<Token*> tokenize(const std::string &code) {
      std::list<Token*> tokens;

      for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
        char ch = code[i];
        if(ch == '(')
          tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
        else if(ch == ')')
          tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
        else if(ch == '"') { // string
          i++;

          size_t token_len = 0;
          while(code[i + token_len] != '"') {
            token_len++;
            if(i + token_len >= code.size()) {
              //TODO: raise an error
            }
          }
          tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
          i += token_len;
        }
        else if(ch == ' ' || ch == '\n')
          ;//skip
        else if(is_number(ch)) {
          size_t token_len = 0;
          while(is_number(code[i + token_len])) {
            token_len++;
            if(i + token_len >= code.size()) {
              // TODO: raise an error
            }
          }

          std::string token_val = code.substr(i, token_len);
          tokens.push_back(new Token(TOKEN_INTEGER, token_val));

          i += token_len - 1;
        }
        else { // symbol
          size_t token_len = 0;
          while(is_symbol(code[i + token_len])) {
            token_len++;
            if(i + token_len >= code.size()) {
              //TODO: raise an error
            }
          }

          std::string token_val = code.substr(i, token_len);
          TokenType token_type;
          if(token_val == "nil")
            token_type = TOKEN_NIL;
          else
            token_type = TOKEN_SYMBOL;

          if(token_type == TOKEN_SYMBOL)
            tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
          else
            tokens.push_back(new Token(token_type));

          i += token_len - 1;
        }
      }

      return tokens;
    }
  };

  class Evaluator {
    std::map<std::string, Expression*> env;

    Expression* eval_expr(Expression* expr) {
      const std::type_info& id = typeid(*expr);
      if(id == typeid(List)) {
        auto list = (List*)expr;
        auto name = ((Symbol*)list->values[0])->value;
        if(name == "print") {
          std::cout << (evaluate(list->values[1]))->lisp_str() << std::endl;
          return new Nil();
        }
        else if(name == "setq") {
          env[regard<Symbol>(list->values[1])->value] = list->values[2];
          return new Nil();
        }
        else if(name == "atom") {
          auto val = evaluate(list->values[1]);
          if(typeid(*val) != typeid(List)) return new T();
          else return new Nil();
        }
        else if(name == "+") {
          Integer* sum = new Integer(0);
          for(size_t i = 1 ; i < list->values.size() ; i++) {
            sum->value += ((Integer*)evaluate(list->values[i]))->value;
          }
          return sum;
        }
        else if(name == "list") {
          std::vector<Expression*> values;
          for(size_t i = 1 ; i < list->values.size() ; i++) {
            values.push_back(evaluate(list->values[i]));
          }
          return new List(values);
        }
      }
      else if(id == typeid(Symbol)) {
        return env[((Symbol*)expr)->value];
      }

      return expr;
    }

  public:
    Expression* evaluate(Expression* expr) {
      return eval_expr(expr);
    }

    template<typename T> T* regard(Expression* expr) {
      if(typeid(*expr) != typeid(T)) {
        throw std::logic_error("illeagl type error: expected " + std::string(typeid(T).name()) + " but " + std::string(typeid(*expr).name()));
      }
      return (T*)expr;
    }
  };
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  Lisp::Parser parser;
  auto exprs = parser.parse(code);

  Lisp::Evaluator evaluator;
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    exprs[i] = evaluator.evaluate(exprs[i]);
  }

  // fake GC
  for(auto expr : objects) {
    delete expr;
  }

  return 0;
}
<|endoftext|>


<commit_before>/* Name:
 * ID:
 * Email:
 */

/*
 * This is code skeleton for COMP5112-17Spring assignment2
 * Compile: g++ -std=c++11 -lpthread -o pthread_dijkstra pthread_dijkstra.cpp
 * Run: ./pthread_dijkstra -n <number of threads> -i <input file>,
 * you will find the output in 'output.txt' file
 */

#include <string>
#include <cassert>
#include <iostream>
#include <fstream>
#include <vector>
#include <climits>
#include <cstring>
#include <algorithm>
#include <sys/time.h>
#include <time.h>
#include <getopt.h>

#include <pthread.h>

using std::string;
using std::cout;
using std::endl;
using std::vector;

/*
 * utils is a namespace for utility functions
 * including I/O (read input file and print results) and one matrix dimension convert(2D->1D) function
 */
namespace utils {
    int num_threads; //number of thread
    int N; //number of vertices
    int *mat; // the adjacency matrix

    string filename; // input file name
    string outputfile; //output file name, default: 'output.txt'

    void print_usage() {
        cout << "Usage:\n" << "\tpthread_dijkstra -n <number of threads> -i <input file>" << endl;
        exit(0);
    }

    int parse_args(int argc, char **argv) {
        filename = "";
        outputfile = "output.txt";
        num_threads = 0;

        int opt;
        if (argc < 2) {
            print_usage();
        }
        while ((opt = getopt(argc, argv, "n:i:o:h")) != EOF) {
            switch (opt) {
                case 'n':
                    num_threads = atoi(optarg);
                    break;
                case 'i':
                    filename = optarg;
                    break;
                case 'o':
                    outputfile = optarg;
                    break;
                case 'h':
                case '?':
                default:
                    print_usage();
            }
        }
        if (filename.length() == 0 || num_threads == 0)
            print_usage();
        return 0;
    }

    /*
     * convert 2-dimension coordinate to 1-dimension
     */
    int convert_dimension_2D_1D(int x, int y) {
        return x * N + y;
    }

    int read_file(string filename) {
        std::ifstream inputf(filename, std::ifstream::in);
        inputf >> N;
        assert(N < (1024 * 1024 *
                    20)); // input matrix should be smaller than 20MB * 20MB (400MB, we don't have two much memory for multi-processors)
        mat = (int *) malloc(N * N * sizeof(int));
        for (int i = 0; i < N; i++)
            for (int j = 0; j < N; j++) {
                inputf >> mat[convert_dimension_2D_1D(i, j)];
            }

        return 0;
    }

    string format_path(int i, int *pred) {
        string out("");
        int current_vertex = i;
        while (current_vertex != 0) {
            string s = std::to_string(current_vertex);
            std::reverse(s.begin(), s.end());
            out = out + s + ">-";
            current_vertex = pred[current_vertex];
        }
        out = out + std::to_string(0);
        std::reverse(out.begin(), out.end());
        return out;
    }

    int print_result(int *dist, int *pred) {
        std::ofstream outputf(outputfile, std::ofstream::out);
        outputf << dist[0];
        for (int i = 1; i < N; i++) {
            outputf << " " << dist[i];
        }
        for (int i = 0; i < N; i++) {
            outputf << "\n";
            if (dist[i] >= 1000000) {
                outputf << "NO PATH";
            } else {
                outputf << format_path(i, pred);
            }
        }
        outputf << endl;
        return 0;
    }
}//namespace utils

//Hint: use pthread condition variable or pthread barrier to do the synchronization
//------You may add helper functions and global variables here------

void dijkstra(int N, int p, int *mat, int *all_dist, int *all_pred) {
    //------your code starts from here------

    //------end of your code------
}

int main(int argc, char **argv) {
    assert(utils::parse_args(argc, argv) == 0);
    assert(utils::read_file(utils::filename) == 0);

    assert(utils::num_threads <= utils::N);
    //`all_dist` stores the distances and `all_pred` stores the predecessors
    int *all_dist;
    int *all_pred;
    all_dist = (int *) calloc(utils::N, sizeof(int));
    all_pred = (int *) calloc(utils::N, sizeof(int));

    //time counter
    timeval start_wall_time_t, end_wall_time_t;
    float ms_wall;

    //start timer
    gettimeofday(&start_wall_time_t, nullptr);

    dijkstra(utils::N, utils::num_threads, utils::mat, all_dist, all_pred);

    //end timer
    gettimeofday(&end_wall_time_t, nullptr);
    ms_wall = ((end_wall_time_t.tv_sec - start_wall_time_t.tv_sec) * 1000 * 1000
               + end_wall_time_t.tv_usec - start_wall_time_t.tv_usec) / 1000.0;

    std::cerr << "Time(ms): " << ms_wall << endl;

    utils::print_result(all_dist, all_pred);

    free(utils::mat);
    free(all_dist);
    free(all_pred);

    return 0;
}
<commit_msg>Delete unwanted data<commit_after><|endoftext|>


<commit_before>/*
 * Copyright (C) 2006-2007 Laurentiu-Gheorghe Crisan
 * Copyright (C) 2006-2007 Marc Boris Duerner
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "iodeviceimpl.h"
#include "cxxtools/ioerror.h"
#include "error.h"
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <cxxtools/log.h>
#include <cxxtools/hdstream.h>

log_define("cxxtools.iodevice.impl")

namespace cxxtools {

const short IODeviceImpl::POLLERR_MASK= POLLERR | POLLHUP | POLLNVAL;
const short IODeviceImpl::POLLIN_MASK= POLLIN;
const short IODeviceImpl::POLLOUT_MASK= POLLOUT;

IODeviceImpl::IODeviceImpl(IODevice& device)
: _device(device)
, _fd(-1)
, _timeout(Selectable::WaitInfinite)
, _pfd(0)
, _sentry(0)
, _errorPending(false)
{ }

IODeviceImpl::~IODeviceImpl()
{
    assert(_pfd == 0);

    if(_sentry)
        _sentry->detach();
}

void IODeviceImpl::open(const std::string& path, IODevice::OpenMode mode, bool inherit)
{
    int flags = O_RDONLY;

    if( (mode & IODevice::Read ) && (mode & IODevice::Write) )
    {
        flags |= O_RDWR;
    }
    else if(mode & IODevice::Write)
    {
        flags |= O_WRONLY;
    }
    else if(mode & IODevice::Read  )
    {
        flags |= O_RDONLY;
    }

    if(mode & IODevice::Async)
        flags |= O_NONBLOCK;

    if(mode & IODevice::Trunc)
        flags |= O_TRUNC;

    flags |=  O_NOCTTY;

    _fd = ::open( path.c_str(), flags );
    if(_fd == -1)
        throw AccessFailed(getErrnoString("open failed"));

    if (!inherit)
    {
        int flags = fcntl(_fd, F_GETFD);
        flags |= FD_CLOEXEC ;
        int ret = fcntl(_fd, F_SETFD, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set FD_CLOEXEC"));
    }

}

void IODeviceImpl::open(int fd, bool isAsync, bool inherit)
{
    _fd = fd;

    if (isAsync)
    {
        int flags = fcntl(_fd, F_GETFL);
        flags |= O_NONBLOCK ;
        int ret = fcntl(_fd, F_SETFL, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set fd to non-blocking"));
    }

    if (!inherit)
    {
        int flags = fcntl(_fd, F_GETFD);
        flags |= FD_CLOEXEC ;
        int ret = fcntl(_fd, F_SETFD, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set FD_CLOEXEC"));
    }

}

void IODeviceImpl::close()
{
    log_debug("close device; fd=" << _fd << " pfd=" << _pfd);

    if(_fd != -1)
    {
        int fd = _fd;
        _fd = -1;
        _pfd = 0;

        while ( ::close(fd) != 0 )
        {
            if( errno != EINTR )
            {
                log_error("close of iodevice failed; errno=" << errno);
                throw IOError(getErrnoString("Could not close file handle"));
            }
        }
    }
}

size_t IODeviceImpl::beginRead(char* buffer, size_t n, bool& eof)
{
    if(_pfd)
    {
        _pfd->events |= POLLIN;
    }

    return 0;
}

size_t IODeviceImpl::endRead(bool& eof)
{
    if(_pfd)
    {
        _pfd->events &= ~POLLIN;
    }

    if (_errorPending)
    {
        _errorPending = false;
        throw IOError("read error");
    }

    return this->read( _device.rbuf(), _device.rbuflen(), eof );
}

size_t IODeviceImpl::read( char* buffer, size_t count, bool& eof )
{
    ssize_t ret = 0;

    while(true)
    {
        ret = ::read( _fd, (void*)buffer, count);

        if(ret > 0)
        {
            log_debug("::read(" << _fd << ", " << count << ") returned " << ret << " => \"" << hexDump(buffer, ret) << '"');
            break;
        }

        log_debug("::read(" << _fd << ", " << count << ") returned " << ret << " errno=" << errno);

        if(ret == 0 || errno == ECONNRESET)
        {
            eof = true;
            return 0;
        }

        if(errno == EINTR)
            continue;

        if(errno != EAGAIN)
            throw IOError(getErrnoString("read failed"));

        pollfd pfd;
        pfd.fd = this->fd();
        pfd.revents = 0;
        pfd.events = POLLIN;

        bool ret = this->wait(_timeout, pfd);
        if(false == ret)
        {
            log_debug("timeout");
            throw IOTimeout();
        }
    }

    return ret;
}

size_t IODeviceImpl::beginWrite(const char* buffer, size_t n)
{
    log_debug("::write(" << _fd << ", buffer, " << n << ')');
    ssize_t ret = ::write(_fd, (const void*)buffer, n);

    log_debug("write returned " << ret);
    if (ret > 0)
        return static_cast<size_t>(ret);

    if (ret == 0 || errno == ECONNRESET || errno == EPIPE)
        throw IOError("lost connection to peer");

    if(_pfd)
    {
        _pfd->events |= POLLOUT;
    }

    return 0;
}

size_t IODeviceImpl::endWrite()
{
    if(_pfd)
    {
        _pfd->events &= ~POLLOUT;
    }

    if (_errorPending)
    {
        _errorPending = false;
        throw IOError("write error");
    }

    if (_device.wavail() > 0)
    {
        log_debug("write pending " << _device.wavail());
        size_t n = _device.wavail();
        return n;
    }

    return this->write( _device.wbuf(), _device.wbuflen() );
}

size_t IODeviceImpl::write( const char* buffer, size_t count )
{
    ssize_t ret = 0;

    while(true)
    {
        log_debug("::write(" << _fd << ", buffer, " << count << ')');

        ret = ::write(_fd, (const void*)buffer, count);
        log_debug("write returned " << ret);
        if(ret > 0)
            break;

        if(ret == 0 || errno == ECONNRESET || errno == EPIPE)
            throw IOError("lost connection to peer");

        if(errno == EINTR)
            continue;

        if(errno != EAGAIN)
            throw IOError(getErrnoString("Could not write to file handle"));

        pollfd pfd;
        pfd.fd = this->fd();
        pfd.revents = 0;
        pfd.events = POLLOUT;

        if (!this->wait(_timeout, pfd))
        {
            throw IOTimeout();
        }
    }

    return static_cast<size_t>(ret);
}

void IODeviceImpl::sigwrite(int sig)
{
    ::write(_fd, (const void*)&sig, sizeof(sig));
}

void IODeviceImpl::cancel()
{
    if(_pfd)
    {
        _pfd->events &= ~(POLLIN|POLLOUT);
    }
}

void IODeviceImpl::sync() const
{
    int ret = fsync(_fd);
    if(ret != 0)
        throw IOError(getErrnoString("Could not sync handle"));
}

void IODeviceImpl::attach(SelectorBase& s)
{

}

void IODeviceImpl::detach(SelectorBase& s)
{
    _pfd = 0;
}

bool IODeviceImpl::wait(Timespan timeout)
{
    if (_device.wavail() > 0)
    {
        _device.outputReady(_device);
        return true;
    }

    pollfd pfd;
    this->initWait(pfd);
    this->wait(timeout, pfd);
    return this->checkPollEvent(pfd);
}

bool IODeviceImpl::wait(Timespan timeout, pollfd& pfd)
{
    int msecs = Milliseconds(timeout) > std::numeric_limits<int>::max()
                    ? std::numeric_limits<int>::max()
                    : int(Milliseconds(timeout).ceil());

    int ret = -1;
    do
    {
        ret = ::poll(&pfd, 1, msecs);
    } while (ret == -1 && errno == EINTR);

    if (ret == -1)
        throw IOError(getErrnoString("poll failed"));

    return ret > 0;
}

void IODeviceImpl::initWait(pollfd& pfd)
{
    pfd.fd = this->fd();
    pfd.revents = 0;
    pfd.events = 0;

    if( _device.reading() )
        pfd.events |= POLLIN;
    if( _device.writing() )
        pfd.events |= POLLOUT;
}

size_t IODeviceImpl::initializePoll(pollfd* pfd, size_t pollSize)
{
    assert(pfd != 0);
    assert(pollSize >= 1);

    this->initWait(*pfd);
    _pfd = pfd;

    return 1;
}

bool IODeviceImpl::checkPollEvent()
{
    // _pfd can be 0 if the device is just added during wait iteration
    if (_pfd == 0)
        return false;

    return this->checkPollEvent(*_pfd);
}

bool IODeviceImpl::checkPollEvent(pollfd& pfd)
{
    log_trace("checkPollEvent");

    bool avail = false;

    DestructionSentry sentry(_sentry);

    if (pfd.revents & POLLERR_MASK)
    {
        _errorPending = true;

        try
        {
            bool reading = _device.reading();
            bool writing = _device.writing();

            if (reading)
            {
                avail = true;
                _device.inputReady(_device);
            }

            if( ! _sentry )
                return avail;

            if (writing)
            {
                avail = true;
                _device.outputReady(_device);
            }

            if( ! _sentry )
                return avail;

            if (!reading && !writing)
            {
                avail = true;
                _device.close();
            }
        }
        catch (...)
        {
            _errorPending = false;
            throw;
        }
        _errorPending = false;

        return avail;
    }

    if( _device.wavail() > 0 || (pfd.revents & POLLOUT_MASK) )
    {
        log_debug("send signal outputReady");
        _device.outputReady(_device);
        avail = true;
    }

    if( ! _sentry )
        return avail;

    if( pfd.revents & POLLIN_MASK )
    {
        log_debug("send signal inputReady");
        _device.inputReady(_device);
        avail = true;
    }

    return avail;
}

}
<commit_msg>fix inifinite wait - was broken after replacing timeouts with cxxtools::Timespan<commit_after>/*
 * Copyright (C) 2006-2007 Laurentiu-Gheorghe Crisan
 * Copyright (C) 2006-2007 Marc Boris Duerner
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * As a special exception, you may use this file as part of a free
 * software library without restriction. Specifically, if other files
 * instantiate templates or use macros or inline functions from this
 * file, or you compile this file and link it with other files to
 * produce an executable, this file does not by itself cause the
 * resulting executable to be covered by the GNU General Public
 * License. This exception does not however invalidate any other
 * reasons why the executable file might be covered by the GNU Library
 * General Public License.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
#include "iodeviceimpl.h"
#include "cxxtools/ioerror.h"
#include "error.h"
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <cxxtools/log.h>
#include <cxxtools/hdstream.h>

log_define("cxxtools.iodevice.impl")

namespace cxxtools {

const short IODeviceImpl::POLLERR_MASK= POLLERR | POLLHUP | POLLNVAL;
const short IODeviceImpl::POLLIN_MASK= POLLIN;
const short IODeviceImpl::POLLOUT_MASK= POLLOUT;

IODeviceImpl::IODeviceImpl(IODevice& device)
: _device(device)
, _fd(-1)
, _timeout(Selectable::WaitInfinite)
, _pfd(0)
, _sentry(0)
, _errorPending(false)
{ }

IODeviceImpl::~IODeviceImpl()
{
    assert(_pfd == 0);

    if(_sentry)
        _sentry->detach();
}

void IODeviceImpl::open(const std::string& path, IODevice::OpenMode mode, bool inherit)
{
    int flags = O_RDONLY;

    if( (mode & IODevice::Read ) && (mode & IODevice::Write) )
    {
        flags |= O_RDWR;
    }
    else if(mode & IODevice::Write)
    {
        flags |= O_WRONLY;
    }
    else if(mode & IODevice::Read  )
    {
        flags |= O_RDONLY;
    }

    if(mode & IODevice::Async)
        flags |= O_NONBLOCK;

    if(mode & IODevice::Trunc)
        flags |= O_TRUNC;

    flags |=  O_NOCTTY;

    _fd = ::open( path.c_str(), flags );
    if(_fd == -1)
        throw AccessFailed(getErrnoString("open failed"));

    if (!inherit)
    {
        int flags = fcntl(_fd, F_GETFD);
        flags |= FD_CLOEXEC ;
        int ret = fcntl(_fd, F_SETFD, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set FD_CLOEXEC"));
    }

}

void IODeviceImpl::open(int fd, bool isAsync, bool inherit)
{
    _fd = fd;

    if (isAsync)
    {
        int flags = fcntl(_fd, F_GETFL);
        flags |= O_NONBLOCK ;
        int ret = fcntl(_fd, F_SETFL, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set fd to non-blocking"));
    }

    if (!inherit)
    {
        int flags = fcntl(_fd, F_GETFD);
        flags |= FD_CLOEXEC ;
        int ret = fcntl(_fd, F_SETFD, flags);
        if(-1 == ret)
            throw IOError(getErrnoString("Could not set FD_CLOEXEC"));
    }

}

void IODeviceImpl::close()
{
    log_debug("close device; fd=" << _fd << " pfd=" << _pfd);

    if(_fd != -1)
    {
        int fd = _fd;
        _fd = -1;
        _pfd = 0;

        while ( ::close(fd) != 0 )
        {
            if( errno != EINTR )
            {
                log_error("close of iodevice failed; errno=" << errno);
                throw IOError(getErrnoString("Could not close file handle"));
            }
        }
    }
}

size_t IODeviceImpl::beginRead(char* buffer, size_t n, bool& eof)
{
    if(_pfd)
    {
        _pfd->events |= POLLIN;
    }

    return 0;
}

size_t IODeviceImpl::endRead(bool& eof)
{
    if(_pfd)
    {
        _pfd->events &= ~POLLIN;
    }

    if (_errorPending)
    {
        _errorPending = false;
        throw IOError("read error");
    }

    return this->read( _device.rbuf(), _device.rbuflen(), eof );
}

size_t IODeviceImpl::read( char* buffer, size_t count, bool& eof )
{
    ssize_t ret = 0;

    while(true)
    {
        ret = ::read( _fd, (void*)buffer, count);

        if(ret > 0)
        {
            log_debug("::read(" << _fd << ", " << count << ") returned " << ret << " => \"" << hexDump(buffer, ret) << '"');
            break;
        }

        log_debug("::read(" << _fd << ", " << count << ") returned " << ret << " errno=" << errno);

        if(ret == 0 || errno == ECONNRESET)
        {
            eof = true;
            return 0;
        }

        if(errno == EINTR)
            continue;

        if(errno != EAGAIN)
            throw IOError(getErrnoString("read failed"));

        pollfd pfd;
        pfd.fd = this->fd();
        pfd.revents = 0;
        pfd.events = POLLIN;

        bool ret = this->wait(_timeout, pfd);
        if(false == ret)
        {
            log_debug("timeout (" << _timeout << ')');
            throw IOTimeout();
        }
    }

    return ret;
}

size_t IODeviceImpl::beginWrite(const char* buffer, size_t n)
{
    log_debug("::write(" << _fd << ", buffer, " << n << ')');
    ssize_t ret = ::write(_fd, (const void*)buffer, n);

    log_debug("write returned " << ret);
    if (ret > 0)
        return static_cast<size_t>(ret);

    if (ret == 0 || errno == ECONNRESET || errno == EPIPE)
        throw IOError("lost connection to peer");

    if(_pfd)
    {
        _pfd->events |= POLLOUT;
    }

    return 0;
}

size_t IODeviceImpl::endWrite()
{
    if(_pfd)
    {
        _pfd->events &= ~POLLOUT;
    }

    if (_errorPending)
    {
        _errorPending = false;
        throw IOError("write error");
    }

    if (_device.wavail() > 0)
    {
        log_debug("write pending " << _device.wavail());
        size_t n = _device.wavail();
        return n;
    }

    return this->write( _device.wbuf(), _device.wbuflen() );
}

size_t IODeviceImpl::write( const char* buffer, size_t count )
{
    ssize_t ret = 0;

    while(true)
    {
        log_debug("::write(" << _fd << ", buffer, " << count << ')');

        ret = ::write(_fd, (const void*)buffer, count);
        log_debug("write returned " << ret);
        if(ret > 0)
            break;

        if(ret == 0 || errno == ECONNRESET || errno == EPIPE)
            throw IOError("lost connection to peer");

        if(errno == EINTR)
            continue;

        if(errno != EAGAIN)
            throw IOError(getErrnoString("Could not write to file handle"));

        pollfd pfd;
        pfd.fd = this->fd();
        pfd.revents = 0;
        pfd.events = POLLOUT;

        if (!this->wait(_timeout, pfd))
        {
            throw IOTimeout();
        }
    }

    return static_cast<size_t>(ret);
}

void IODeviceImpl::sigwrite(int sig)
{
    ::write(_fd, (const void*)&sig, sizeof(sig));
}

void IODeviceImpl::cancel()
{
    if(_pfd)
    {
        _pfd->events &= ~(POLLIN|POLLOUT);
    }
}

void IODeviceImpl::sync() const
{
    int ret = fsync(_fd);
    if(ret != 0)
        throw IOError(getErrnoString("Could not sync handle"));
}

void IODeviceImpl::attach(SelectorBase& s)
{

}

void IODeviceImpl::detach(SelectorBase& s)
{
    _pfd = 0;
}

bool IODeviceImpl::wait(Timespan timeout)
{
    if (_device.wavail() > 0)
    {
        _device.outputReady(_device);
        return true;
    }

    pollfd pfd;
    this->initWait(pfd);
    this->wait(timeout, pfd);
    return this->checkPollEvent(pfd);
}

bool IODeviceImpl::wait(Timespan timeout, pollfd& pfd)
{
    int msecs = timeout < Timespan(0) ? -1
              : Milliseconds(timeout) > std::numeric_limits<int>::max()
                            ? std::numeric_limits<int>::max()
              : int(Milliseconds(timeout).ceil());

    log_debug("wait " << msecs << "ms");
    int ret = -1;
    do
    {
        ret = ::poll(&pfd, 1, msecs);
    } while (ret == -1 && errno == EINTR);

    if (ret == -1)
        throw IOError(getErrnoString("poll failed"));

    return ret > 0;
}

void IODeviceImpl::initWait(pollfd& pfd)
{
    pfd.fd = this->fd();
    pfd.revents = 0;
    pfd.events = 0;

    if( _device.reading() )
        pfd.events |= POLLIN;
    if( _device.writing() )
        pfd.events |= POLLOUT;
}

size_t IODeviceImpl::initializePoll(pollfd* pfd, size_t pollSize)
{
    assert(pfd != 0);
    assert(pollSize >= 1);

    this->initWait(*pfd);
    _pfd = pfd;

    return 1;
}

bool IODeviceImpl::checkPollEvent()
{
    // _pfd can be 0 if the device is just added during wait iteration
    if (_pfd == 0)
        return false;

    return this->checkPollEvent(*_pfd);
}

bool IODeviceImpl::checkPollEvent(pollfd& pfd)
{
    log_trace("checkPollEvent");

    bool avail = false;

    DestructionSentry sentry(_sentry);

    if (pfd.revents & POLLERR_MASK)
    {
        _errorPending = true;

        try
        {
            bool reading = _device.reading();
            bool writing = _device.writing();

            if (reading)
            {
                avail = true;
                _device.inputReady(_device);
            }

            if( ! _sentry )
                return avail;

            if (writing)
            {
                avail = true;
                _device.outputReady(_device);
            }

            if( ! _sentry )
                return avail;

            if (!reading && !writing)
            {
                avail = true;
                _device.close();
            }
        }
        catch (...)
        {
            _errorPending = false;
            throw;
        }
        _errorPending = false;

        return avail;
    }

    if( _device.wavail() > 0 || (pfd.revents & POLLOUT_MASK) )
    {
        log_debug("send signal outputReady");
        _device.outputReady(_device);
        avail = true;
    }

    if( ! _sentry )
        return avail;

    if( pfd.revents & POLLIN_MASK )
    {
        log_debug("send signal inputReady");
        _device.inputReady(_device);
        avail = true;
    }

    return avail;
}

}
<|endoftext|>