<commit_before>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WorkerAsyncFileSystemChromium.h"

#if ENABLE(FILE_SYSTEM) && ENABLE(WORKERS)

#include "AsyncFileSystemCallbacks.h"
#include "BlobURL.h"
#include "FileMetadata.h"
#include "FileSystem.h"
#include "NotImplemented.h"
#include "WebFileSystemCallbacksImpl.h"
#include "WebFileWriter.h"
#include "WorkerAsyncFileWriterChromium.h"
#include "WorkerContext.h"
#include "WorkerFileSystemCallbacksBridge.h"
#include "WorkerScriptController.h"
#include "WorkerThread.h"
#include <public/WebFileSystem.h>
#include <wtf/text/CString.h>

using namespace WebKit;

namespace WebCore {

static const char fileSystemOperationsMode[] = "fileSystemOperationsMode";

WorkerAsyncFileSystemChromium::WorkerAsyncFileSystemChromium(ScriptExecutionContext* context, FileSystemSynchronousType synchronousType)
    : m_scriptExecutionContext(context)
    , m_workerContext(static_cast<WorkerContext*>(context))
    , m_synchronousType(synchronousType)
{
    ASSERT(m_scriptExecutionContext->isWorkerContext());

    m_workerLoaderProxy = &m_workerContext->thread()->workerLoaderProxy();
}

WorkerAsyncFileSystemChromium::~WorkerAsyncFileSystemChromium()
{
}

bool WorkerAsyncFileSystemChromium::waitForOperationToComplete()
{
    if (!m_bridgeForCurrentOperation)
        return false;

    RefPtr<WorkerFileSystemCallbacksBridge> bridge = m_bridgeForCurrentOperation.release();
    if (m_workerContext->thread()->runLoop().runInMode(m_workerContext, m_modeForCurrentOperation) == MessageQueueTerminated) {
        bridge->stop();
        return false;
    }
    return true;
}

void WorkerAsyncFileSystemChromium::move(const KURL& sourcePath, const KURL& destinationPath, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postMoveToMainThread(m_webFileSystem, sourcePath, destinationPath, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::copy(const KURL& sourcePath, const KURL& destinationPath, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCopyToMainThread(m_webFileSystem, sourcePath, destinationPath, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::remove(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postRemoveToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::removeRecursively(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postRemoveRecursivelyToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::readMetadata(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postReadMetadataToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createFile(const KURL& path, bool exclusive, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateFileToMainThread(m_webFileSystem, path, exclusive, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createDirectory(const KURL& path, bool exclusive, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateDirectoryToMainThread(m_webFileSystem, path, exclusive, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::fileExists(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postFileExistsToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::directoryExists(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postDirectoryExistsToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::readDirectory(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postReadDirectoryToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

class WorkerFileWriterHelperCallbacks : public AsyncFileSystemCallbacks {
public:
    static PassOwnPtr<WorkerFileWriterHelperCallbacks> create(AsyncFileWriterClient* client, const WebURL& path, WebKit::WebFileSystem* webFileSystem, PassOwnPtr<WebCore::AsyncFileSystemCallbacks> callbacks, WorkerContext* workerContext)
    {
        return adoptPtr(new WorkerFileWriterHelperCallbacks(client, path, webFileSystem, callbacks, workerContext));
    }

    virtual void didReadMetadata(const FileMetadata& metadata)
    {
        ASSERT(m_callbacks);
        if (metadata.type != FileMetadata::TypeFile || metadata.length < 0)
            m_callbacks->didFail(WebKit::WebFileErrorInvalidState);
        else {
            OwnPtr<WorkerAsyncFileWriterChromium> asyncFileWriterChromium = WorkerAsyncFileWriterChromium::create(m_webFileSystem, m_path, m_workerContext, m_client, WorkerAsyncFileWriterChromium::Asynchronous);
            m_callbacks->didCreateFileWriter(asyncFileWriterChromium.release(), metadata.length);
        }
    }

    virtual void didFail(int code)
    {
        ASSERT(m_callbacks);
        m_callbacks->didFail(code);
    }

private:
    WorkerFileWriterHelperCallbacks(AsyncFileWriterClient* client, const WebURL& path, WebKit::WebFileSystem* webFileSystem, PassOwnPtr<WebCore::AsyncFileSystemCallbacks> callbacks, WorkerContext* workerContext)
        : m_client(client)
        , m_path(path)
        , m_webFileSystem(webFileSystem)
        , m_callbacks(callbacks)
        , m_workerContext(workerContext)
    {
    }

    AsyncFileWriterClient* m_client;
    WebURL m_path;
    WebKit::WebFileSystem* m_webFileSystem;
    OwnPtr<WebCore::AsyncFileSystemCallbacks> m_callbacks;
    WorkerContext* m_workerContext;
};

void WorkerAsyncFileSystemChromium::createWriter(AsyncFileWriterClient* client, const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(WorkerFileWriterHelperCallbacks::create(client, path, m_webFileSystem, callbacks, m_workerContext))->postReadMetadataToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createSnapshotFileAndReadMetadata(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateSnapshotFileToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

PassRefPtr<WorkerFileSystemCallbacksBridge> WorkerAsyncFileSystemChromium::createWorkerFileSystemCallbacksBridge(PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    ASSERT(m_synchronousType == AsynchronousFileSystem || !m_bridgeForCurrentOperation);
    (void)m_synchronousType; // Needed for release builds, don't delete.

    m_modeForCurrentOperation = fileSystemOperationsMode;
    m_modeForCurrentOperation.append(String::number(m_workerContext->thread()->runLoop().createUniqueId()));

    m_bridgeForCurrentOperation = WorkerFileSystemCallbacksBridge::create(m_workerLoaderProxy, m_scriptExecutionContext, new WebKit::WebFileSystemCallbacksImpl(callbacks));
    return m_bridgeForCurrentOperation;
}

} // namespace WebCore

#endif // ENABLE(FILE_SYSTEM)
<commit_msg>Unreviewed build fix.<commit_after>/*
 * Copyright (C) 2010 Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "WorkerAsyncFileSystemChromium.h"

#if ENABLE(FILE_SYSTEM) && ENABLE(WORKERS)

#include "AsyncFileSystemCallbacks.h"
#include "BlobURL.h"
#include "FileMetadata.h"
#include "FileSystem.h"
#include "NotImplemented.h"
#include "WebFileSystemCallbacksImpl.h"
#include "WebFileWriter.h"
#include "WorkerAsyncFileWriterChromium.h"
#include "WorkerContext.h"
#include "WorkerFileSystemCallbacksBridge.h"
#include "WorkerScriptController.h"
#include "WorkerThread.h"
#include <public/WebFileSystem.h>
#include <wtf/text/CString.h>

using namespace WebKit;

namespace WebCore {

static const char fileSystemOperationsMode[] = "fileSystemOperationsMode";

WorkerAsyncFileSystemChromium::WorkerAsyncFileSystemChromium(ScriptExecutionContext* context, FileSystemSynchronousType synchronousType)
    : m_scriptExecutionContext(context)
    , m_workerContext(static_cast<WorkerContext*>(context))
    , m_synchronousType(synchronousType)
{
    ASSERT(m_scriptExecutionContext->isWorkerContext());

    m_workerLoaderProxy = &m_workerContext->thread()->workerLoaderProxy();
}

WorkerAsyncFileSystemChromium::~WorkerAsyncFileSystemChromium()
{
}

bool WorkerAsyncFileSystemChromium::waitForOperationToComplete()
{
    if (!m_bridgeForCurrentOperation)
        return false;

    RefPtr<WorkerFileSystemCallbacksBridge> bridge = m_bridgeForCurrentOperation.release();
    if (m_workerContext->thread()->runLoop().runInMode(m_workerContext, m_modeForCurrentOperation) == MessageQueueTerminated) {
        bridge->stop();
        return false;
    }
    return true;
}

void WorkerAsyncFileSystemChromium::move(const KURL& sourcePath, const KURL& destinationPath, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postMoveToMainThread(m_webFileSystem, sourcePath, destinationPath, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::copy(const KURL& sourcePath, const KURL& destinationPath, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCopyToMainThread(m_webFileSystem, sourcePath, destinationPath, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::remove(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postRemoveToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::removeRecursively(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postRemoveRecursivelyToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::readMetadata(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postReadMetadataToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createFile(const KURL& path, bool exclusive, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateFileToMainThread(m_webFileSystem, path, exclusive, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createDirectory(const KURL& path, bool exclusive, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateDirectoryToMainThread(m_webFileSystem, path, exclusive, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::fileExists(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postFileExistsToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::directoryExists(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postDirectoryExistsToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::readDirectory(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postReadDirectoryToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

class WorkerFileWriterHelperCallbacks : public AsyncFileSystemCallbacks {
public:
    static PassOwnPtr<WorkerFileWriterHelperCallbacks> create(AsyncFileWriterClient* client, const WebURL& path, WebKit::WebFileSystem* webFileSystem, PassOwnPtr<WebCore::AsyncFileSystemCallbacks> callbacks, WorkerContext* workerContext)
    {
        return adoptPtr(new WorkerFileWriterHelperCallbacks(client, path, webFileSystem, callbacks, workerContext));
    }

    virtual void didReadMetadata(const FileMetadata& metadata)
    {
        ASSERT(m_callbacks);
        if (metadata.type != FileMetadata::TypeFile || metadata.length < 0)
            m_callbacks->didFail(WebKit::WebFileErrorInvalidState);
        else {
            OwnPtr<WorkerAsyncFileWriterChromium> asyncFileWriterChromium = WorkerAsyncFileWriterChromium::create(m_webFileSystem, m_path, m_workerContext, m_client, WorkerAsyncFileWriterChromium::Asynchronous);
            m_callbacks->didCreateFileWriter(asyncFileWriterChromium.release(), metadata.length);
        }
    }

    virtual void didFail(int code)
    {
        ASSERT(m_callbacks);
        m_callbacks->didFail(code);
    }

private:
    WorkerFileWriterHelperCallbacks(AsyncFileWriterClient* client, const WebURL& path, WebKit::WebFileSystem* webFileSystem, PassOwnPtr<WebCore::AsyncFileSystemCallbacks> callbacks, WorkerContext* workerContext)
        : m_client(client)
        , m_path(path)
        , m_webFileSystem(webFileSystem)
        , m_callbacks(callbacks)
        , m_workerContext(workerContext)
    {
    }

    AsyncFileWriterClient* m_client;
    WebURL m_path;
    WebKit::WebFileSystem* m_webFileSystem;
    OwnPtr<WebCore::AsyncFileSystemCallbacks> m_callbacks;
    WorkerContext* m_workerContext;
};

void WorkerAsyncFileSystemChromium::createWriter(AsyncFileWriterClient* client, const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(WorkerFileWriterHelperCallbacks::create(client, path, m_webFileSystem, callbacks, m_workerContext))->postReadMetadataToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

void WorkerAsyncFileSystemChromium::createSnapshotFileAndReadMetadata(const KURL& path, PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    createWorkerFileSystemCallbacksBridge(callbacks)->postCreateSnapshotFileToMainThread(m_webFileSystem, path, m_modeForCurrentOperation);
}

PassRefPtr<WorkerFileSystemCallbacksBridge> WorkerAsyncFileSystemChromium::createWorkerFileSystemCallbacksBridge(PassOwnPtr<AsyncFileSystemCallbacks> callbacks)
{
    ASSERT_UNUSED(m_synchronousType, m_synchronousType == AsynchronousFileSystem || !m_bridgeForCurrentOperation);

    m_modeForCurrentOperation = fileSystemOperationsMode;
    m_modeForCurrentOperation.append(String::number(m_workerContext->thread()->runLoop().createUniqueId()));

    m_bridgeForCurrentOperation = WorkerFileSystemCallbacksBridge::create(m_workerLoaderProxy, m_scriptExecutionContext, new WebKit::WebFileSystemCallbacksImpl(callbacks));
    return m_bridgeForCurrentOperation;
}

} // namespace WebCore

#endif // ENABLE(FILE_SYSTEM)
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/lattice/util/reference_line_matcher.h"

#include <algorithm>
#include <cmath>
#include <vector>

#include "glog/logging.h"
#include "modules/common/math/math_utils.h"
#include "modules/planning/common/planning_util.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::PathPoint;
using apollo::planning::util::InterpolateUsingLinearApproximation;

PathPoint ReferenceLineMatcher::MatchToReferenceLine(
    const std::vector<PathPoint>& reference_line, const double x,
    const double y) {
  CHECK_GT(reference_line.size(), 0);

  auto func_distance_square =
      [](const PathPoint& point, const double x, const double y) {
    double dx = point.x() - x;
    double dy = point.y() - y;
    return dx * dx + dy * dy;
  };

  double distance_min = func_distance_square(reference_line.front(), x, y);
  std::size_t index_min = 0;

  for (std::size_t i = 1; i < reference_line.size(); ++i) {
    double distance_temp = func_distance_square(reference_line[i], x, y);
    if (distance_temp < distance_min) {
      distance_min = distance_temp;
      index_min = i;
    }
  }

  std::size_t index_start = (index_min == 0) ? index_min : index_min - 1;
  std::size_t index_end =
      (index_min + 1 == reference_line.size()) ? index_min : index_min + 1;

  if (index_start == index_end) {
    return reference_line[index_start];
  }

  return FindProjectionPoint(reference_line[index_start],
                             reference_line[index_end], x, y);
}

std::pair<double, double> ReferenceLineMatcher::GetReferenceLineCoordinate(
    const std::vector<PathPoint>& reference_line, const double x,
    const double y) {
  auto matched_path_point = MatchToReferenceLine(reference_line, x, y);
  double lane_heading = matched_path_point.theta();
  double lane_x = matched_path_point.x();
  double lane_y = matched_path_point.y();
  double delta_x = x - lane_x;
  double delta_y = y - lane_y;
  double side = std::cos(lane_heading) * delta_y -
                std::sin(lane_heading) * delta_x;
  std::pair<double, double> relative_coordinate;
  relative_coordinate.first = matched_path_point.s();
  if (side > FLAGS_lattice_epsilon) {
    relative_coordinate.second = std::hypot(delta_x, delta_y);
  } else {
    relative_coordinate.second = -std::hypot(delta_x, delta_y);
  }
  return relative_coordinate;
}

PathPoint ReferenceLineMatcher::MatchToReferenceLine(
    const std::vector<PathPoint>& reference_line, const double s) {
  auto comp =
      [](const PathPoint& point, const double s) { return point.s() < s; };

  auto it_lower =
      std::lower_bound(reference_line.begin(), reference_line.end(), s, comp);
  if (it_lower == reference_line.begin()) {
    return reference_line.front();
  } else if (it_lower == reference_line.end()) {
    return reference_line.back();
  }

  // interpolate between it_lower - 1 and it_lower
  // return interpolate(*(it_lower - 1), *it_lower, s);
  return InterpolateUsingLinearApproximation(*(it_lower - 1), *it_lower, s);
}

PathPoint ReferenceLineMatcher::FindProjectionPoint(const PathPoint& p0,
                                                    const PathPoint& p1,
                                                    const double x,
                                                    const double y) {
  double v0x = x - p0.x();
  double v0y = y - p0.y();

  double v1x = p1.x() - p0.x();
  double v1y = p1.y() - p0.y();

  double v1_norm = std::sqrt(v1x * v1x + v1y * v1y);
  double dot = v0x * v1x + v0y * v1y;

  double delta_s = dot / v1_norm;
  return InterpolateUsingLinearApproximation(p0, p1, p0.s() + delta_s);
}

}  // namespace planning
}  // namespace apollo
<commit_msg>planning: minor code restruction on reference line matcher<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/lattice/util/reference_line_matcher.h"

#include <algorithm>
#include <cmath>
#include <vector>

#include "glog/logging.h"
#include "modules/common/math/math_utils.h"
#include "modules/planning/common/planning_util.h"
#include "modules/planning/common/planning_gflags.h"

namespace apollo {
namespace planning {

using apollo::common::PathPoint;
using apollo::planning::util::InterpolateUsingLinearApproximation;

PathPoint ReferenceLineMatcher::MatchToReferenceLine(
    const std::vector<PathPoint>& reference_line, const double x,
    const double y) {
  CHECK_GT(reference_line.size(), 0);

  auto func_distance_square =
      [](const PathPoint& point, const double x, const double y) {
    double dx = point.x() - x;
    double dy = point.y() - y;
    return dx * dx + dy * dy;
  };

  double distance_min = func_distance_square(reference_line.front(), x, y);
  std::size_t index_min = 0;

  for (std::size_t i = 1; i < reference_line.size(); ++i) {
    double distance_temp = func_distance_square(reference_line[i], x, y);
    if (distance_temp < distance_min) {
      distance_min = distance_temp;
      index_min = i;
    }
  }

  std::size_t index_start = (index_min == 0) ? index_min : index_min - 1;
  std::size_t index_end =
      (index_min + 1 == reference_line.size()) ? index_min : index_min + 1;

  if (index_start == index_end) {
    return reference_line[index_start];
  }

  return FindProjectionPoint(reference_line[index_start],
                             reference_line[index_end], x, y);
}

std::pair<double, double> ReferenceLineMatcher::GetReferenceLineCoordinate(
    const std::vector<PathPoint>& reference_line, const double x,
    const double y) {
  auto matched_path_point = MatchToReferenceLine(reference_line, x, y);
  double rtheta = matched_path_point.theta();
  double rx = matched_path_point.x();
  double ry = matched_path_point.y();
  double delta_x = x - rx;
  double delta_y = y - ry;
  double side = std::cos(rtheta) * delta_y -
                std::sin(rtheta) * delta_x;
  std::pair<double, double> relative_coordinate;
  relative_coordinate.first = matched_path_point.s();
  relative_coordinate.second = std::copysign(std::hypot(delta_x, delta_y),
                                             side);
  return relative_coordinate;
}

PathPoint ReferenceLineMatcher::MatchToReferenceLine(
    const std::vector<PathPoint>& reference_line, const double s) {
  auto comp =
      [](const PathPoint& point, const double s) { return point.s() < s; };

  auto it_lower =
      std::lower_bound(reference_line.begin(), reference_line.end(), s, comp);
  if (it_lower == reference_line.begin()) {
    return reference_line.front();
  } else if (it_lower == reference_line.end()) {
    return reference_line.back();
  }

  // interpolate between it_lower - 1 and it_lower
  // return interpolate(*(it_lower - 1), *it_lower, s);
  return InterpolateUsingLinearApproximation(*(it_lower - 1), *it_lower, s);
}

PathPoint ReferenceLineMatcher::FindProjectionPoint(const PathPoint& p0,
                                                    const PathPoint& p1,
                                                    const double x,
                                                    const double y) {
  double v0x = x - p0.x();
  double v0y = y - p0.y();

  double v1x = p1.x() - p0.x();
  double v1y = p1.y() - p0.y();

  double v1_norm = std::sqrt(v1x * v1x + v1y * v1y);
  double dot = v0x * v1x + v0y * v1y;

  double delta_s = dot / v1_norm;
  return InterpolateUsingLinearApproximation(p0, p1, p0.s() + delta_s);
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


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

#include <memory>
#include <string>
#include <gtest/gtest.h>
#include <boost/thread.hpp>

#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/DataStructures/DataGroupBuilder.h"
#include "SurgSim/Devices/DeviceFilters/BoolToScalar.h"
#include "SurgSim/Input/CommonDevice.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Testing/MockInputOutput.h"

namespace SurgSim
{

namespace Devices
{

using namespace DataStructures;

class BoolToScalarFilterTest : public testing::Test
{
public:

	void SetUp()
	{
		// values for default buttons
		builder.addBoolean(SurgSim::DataStructures::Names::BUTTON_1);
		builder.addBoolean(SurgSim::DataStructures::Names::BUTTON_2);
		builder.addScalar(SurgSim::DataStructures::Names::TOOLDOF);

		defaultData = builder.createData();
	}

	DataStructures::DataGroupBuilder builder;
	DataStructures::DataGroup defaultData;
};

TEST_F(BoolToScalarFilterTest, GeneralSetters)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");

	filter->setValue("Value", 0.5);
	EXPECT_DOUBLE_EQ(0.5, filter->getValue<double>("Value"));

	filter->setValue("Scale", 4.0);
	EXPECT_DOUBLE_EQ(4.0, filter->getValue<double>("Scale"));

	filter->setValue("Clamping", false);
	EXPECT_EQ(false, filter->getValue<bool>("Clamping"));

	filter->setValue("IncreaseField", std::string("IncreaseField"));
	EXPECT_EQ("IncreaseField", filter->getValue<std::string>("IncreaseField"));
	filter->setValue("DecreaseField", "DecreaseField");
	EXPECT_EQ("DecreaseField", filter->getValue<std::string>("DecreaseField"));
	filter->setValue("TargetField", "TargetField");
	EXPECT_EQ("TargetField", filter->getValue<std::string>("TargetField"));
}

TEST_F(BoolToScalarFilterTest, SetRange)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	auto expectedRange = std::make_pair(5.0, 6.0);
	filter->setValue("Range", expectedRange);
	auto resultRange = filter->getValue<std::pair<double, double>>("Range");
	EXPECT_DOUBLE_EQ(expectedRange.first, resultRange.first);
	EXPECT_DOUBLE_EQ(expectedRange.second, resultRange.second);

	// Reverse the range if it's [max, min]
	auto inputRange = std::make_pair(10.0, 1.0);
	expectedRange = std::make_pair(1.0, 10.0);
	filter->setRange(inputRange);
	resultRange = filter->getRange();
	EXPECT_DOUBLE_EQ(expectedRange.first, resultRange.first);
	EXPECT_DOUBLE_EQ(expectedRange.second, resultRange.second);
}

TEST_F(BoolToScalarFilterTest, DataGroupHandling)
{
	{
		SCOPED_TRACE("Valid Data");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		EXPECT_NO_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Invalid IncreasField");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		filter->setIncreaseField("wrongIncrease");
		EXPECT_ANY_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Invalid IncreasField");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		filter->setDecreaseField("wrongDecrease");
		EXPECT_ANY_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Append Target");
		DataStructures::DataGroupBuilder builder;
		builder.addBoolean(Names::BUTTON_1);
		builder.addBoolean(Names::BUTTON_2);
		auto data = builder.createData();
		auto filter = std::make_shared<BoolToScalar>("Filter");
		EXPECT_NO_THROW(filter->initializeInput("device", data));
	}
}

TEST_F(BoolToScalarFilterTest, UpdateTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(2.0);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 2 (scale)
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_NEAR(0.5, value, 0.1);

	// Switiching the buttons, running for .125 of a second so the value should go down by 0.125 * 2 (scale)
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	// prevent accumulated error in the test
	filter->setValue(0.5);
	boost::this_thread::sleep(boost::posix_time::milliseconds(125));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_NEAR(0.25, value, 0.1);
}

TEST_F(BoolToScalarFilterTest, ClampTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(10.0);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 10 (scale)
	// but it's clamped to [0,1]
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_DOUBLE_EQ(1.0, value);

	// Switiching the buttons, running for .25 of a second so the value should go down by 0.25 * 10 (scale)
	// but it's clamped to [0,]1
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_DOUBLE_EQ(0.0, value);
}

TEST_F(BoolToScalarFilterTest, UnClampedTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(10.0);
	filter->setClamping(false);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 10 (scale)
	// but it's not clampe
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_TRUE(value > 2.0);

	// Switiching the buttons, running for .25 of a second so the value should go down by 0.25 * 10 (scale)
	// but it's clamped to [0,]1
	filter->setValue(0.5);
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_TRUE(value < 0.0);
}

}
}

<commit_msg>Fix compilation errors<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2013-2016, SimQuest Solutions Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>
#include <string>
#include <gtest/gtest.h>
#include <boost/thread.hpp>

#include "SurgSim/DataStructures/DataGroup.h"
#include "SurgSim/DataStructures/DataGroupBuilder.h"
#include "SurgSim/Devices/DeviceFilters/BoolToScalar.h"
#include "SurgSim/Input/CommonDevice.h"
#include "SurgSim/Math/Matrix.h"
#include "SurgSim/Testing/MockInputOutput.h"

namespace SurgSim
{

namespace Devices
{

using namespace DataStructures;

class BoolToScalarFilterTest : public testing::Test
{
public:

	void SetUp()
	{
		// values for default buttons
		builder.addBoolean(SurgSim::DataStructures::Names::BUTTON_1);
		builder.addBoolean(SurgSim::DataStructures::Names::BUTTON_2);
		builder.addScalar(SurgSim::DataStructures::Names::TOOLDOF);

		defaultData = builder.createData();
	}

	DataStructures::DataGroupBuilder builder;
	DataStructures::DataGroup defaultData;
};

TEST_F(BoolToScalarFilterTest, GeneralSetters)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");

	filter->setValue("Scalar", 0.5);
	EXPECT_DOUBLE_EQ(0.5, filter->getValue<double>("Scalar"));

	filter->setValue("Scale", 4.0);
	EXPECT_DOUBLE_EQ(4.0, filter->getValue<double>("Scale"));

	filter->setValue("Clamping", false);
	EXPECT_EQ(false, filter->getValue<bool>("Clamping"));

	filter->setValue("IncreaseField", std::string("IncreaseField"));
	EXPECT_EQ("IncreaseField", filter->getValue<std::string>("IncreaseField"));
	filter->setValue("DecreaseField", "DecreaseField");
	EXPECT_EQ("DecreaseField", filter->getValue<std::string>("DecreaseField"));
	filter->setValue("TargetField", "TargetField");
	EXPECT_EQ("TargetField", filter->getValue<std::string>("TargetField"));
}

TEST_F(BoolToScalarFilterTest, SetRange)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	auto expectedRange = std::make_pair(5.0, 6.0);
	filter->setValue("Range", expectedRange);
	auto resultRange = filter->getValue<std::pair<double, double>>("Range");
	EXPECT_DOUBLE_EQ(expectedRange.first, resultRange.first);
	EXPECT_DOUBLE_EQ(expectedRange.second, resultRange.second);

	// Reverse the range if it's [max, min]
	auto inputRange = std::make_pair(10.0, 1.0);
	expectedRange = std::make_pair(1.0, 10.0);
	filter->setRange(inputRange);
	resultRange = filter->getRange();
	EXPECT_DOUBLE_EQ(expectedRange.first, resultRange.first);
	EXPECT_DOUBLE_EQ(expectedRange.second, resultRange.second);
}

TEST_F(BoolToScalarFilterTest, DataGroupHandling)
{
	{
		SCOPED_TRACE("Valid Data");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		EXPECT_NO_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Invalid IncreasField");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		filter->setIncreaseField("wrongIncrease");
		EXPECT_ANY_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Invalid IncreasField");
		auto filter = std::make_shared<BoolToScalar>("Filter");
		filter->setDecreaseField("wrongDecrease");
		EXPECT_ANY_THROW(filter->initializeInput("device", defaultData));
	}
	{
		SCOPED_TRACE("Append Target");
		DataStructures::DataGroupBuilder builder;
		builder.addBoolean(Names::BUTTON_1);
		builder.addBoolean(Names::BUTTON_2);
		auto data = builder.createData();
		auto filter = std::make_shared<BoolToScalar>("Filter");
		EXPECT_NO_THROW(filter->initializeInput("device", data));
	}
}

TEST_F(BoolToScalarFilterTest, UpdateTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(2.0);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 2 (scale)
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_NEAR(0.5, value, 0.1);

	// Switiching the buttons, running for .125 of a second so the value should go down by 0.125 * 2 (scale)
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	// prevent accumulated error in the test
	filter->setScalar(0.5);
	boost::this_thread::sleep(boost::posix_time::milliseconds(125));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_NEAR(0.25, value, 0.1);
}

TEST_F(BoolToScalarFilterTest, ClampTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(10.0);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 10 (scale)
	// but it's clamped to [0,1]
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_DOUBLE_EQ(1.0, value);

	// Switiching the buttons, running for .25 of a second so the value should go down by 0.25 * 10 (scale)
	// but it's clamped to [0,]1
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_DOUBLE_EQ(0.0, value);
}

TEST_F(BoolToScalarFilterTest, UnClampedTest)
{
	auto filter = std::make_shared<BoolToScalar>("Filter");
	filter->setScale(10.0);
	filter->setClamping(false);
	auto resultData = defaultData;
	defaultData.booleans().set(Names::BUTTON_1, false);
	defaultData.booleans().set(Names::BUTTON_2, true);
	double value;
	filter->initializeInput("device", defaultData);

	// Running .25 of a second we expect the value to go up .. by 0.25 * 10 (scale)
	// but it's not clampe
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_TRUE(value > 2.0);

	// Switiching the buttons, running for .25 of a second so the value should go down by 0.25 * 10 (scale)
	// but it's clamped to [0,]1
	filter->setScalar(0.5);
	defaultData.booleans().set(Names::BUTTON_1, true);
	defaultData.booleans().set(Names::BUTTON_2, false);
	boost::this_thread::sleep(boost::posix_time::milliseconds(250));
	filter->filterInput("device", defaultData, &resultData);
	resultData.scalars().get(Names::TOOLDOF, &value);
	EXPECT_TRUE(value < 0.0);
}

}
}

<|endoftext|>


<commit_before>

#include "luiBaseLayout.h"

#include "pstrtod.h"
#include <sstream>

TypeHandle LUIBaseLayout::_type_handle;
NotifyCategoryDef(luiBaseLayout, ":lui");

LUIBaseLayout::LUIBaseLayout(PyObject* self) : LUIObject(self), _spacing(0.0f)
{
}

void LUIBaseLayout::add(PT(LUIBaseElement) object, const string& cell_mode) {
  if (object->has_parent()) {
    luiBaseLayout_cat.error() << "Cannot call add() with an object which already has a parent!" << endl;
    return;
  }

  add_cell(object, construct_cell(cell_mode));
}

void LUIBaseLayout::add(PT(LUIBaseElement) object, float cell_height) {
  Cell cell = { CM_fixed, cell_height, NULL };
  add_cell(object, cell);
}

LUIObject* LUIBaseLayout::add_cell(PT(LUIBaseElement) object, Cell cell) {
  // Construct cell container object
  LUIObject* container = new LUIObject(NULL);
  add_child(container);
  if (object)
    container->add_child(object);
  container->set_debug_name("LUILayoutCell");
  cell.node = container;
  init_container(container);
  _cells.push_back(cell);
  return container;
}

PT(LUIObject) LUIBaseLayout::cell(const string& cell_mode) {
  return add_cell(NULL, construct_cell(cell_mode));
}

PT(LUIObject) LUIBaseLayout::cell(float cell_height) {
  Cell cell = { CM_fixed, cell_height, NULL };
  return add_cell(NULL, cell);
}

PT(LUIObject) LUIBaseLayout::cell() {
  Cell cell = { CM_fit, 0.0f, NULL };
  return add_cell(NULL, cell);
}

bool check_int(const string& str) {
  for (auto it = str.begin(); it != str.end(); ++it) {
    if (*it < '0' || *it > '9')
      return false;
  }
  return true;
}

int parse_int(const string& str) {
  // Assumes valid int
  int result = 0;
  istringstream( str ) >> result;
  return result;
}

LUIBaseLayout::Cell LUIBaseLayout::construct_cell(const string& cell_mode) {
  Cell cell = { CM_fit, 0.0f, NULL };

  // Fit
  if (cell_mode == "?") {
    cell.mode = CM_fit;
    return cell;
  }

  // Fill
  if (cell_mode == "*") {
    cell.mode = CM_fill;
    return cell;
  }

  // Percentage
  if (cell_mode.back() == '%') {
    cell.mode = CM_percentage;

    // Parse payload
    string val = cell_mode.substr(0, cell_mode.size() - 1);
    char* endptr;
    double d_val = pstrtod(val.c_str(), &endptr);

    if (*endptr != 0) {
      luiBaseLayout_cat.error() << "Could not parse float: '" << val << "'" << endl;
      d_val = 0.0;
    }
    cell.payload = (float)(d_val / 100.0);
    return cell;
  }

  // Assume pixels otherwise
  if (check_int(cell_mode)) {
    cell.mode = CM_fixed;
    cell.payload = parse_int(cell_mode);
    return cell;
  }

  luiBaseLayout_cat.error() << "Invalid cell mode: '" << cell_mode << "'" << endl;
  return cell;
}

void LUIBaseLayout::update_layout() {
  // First, get available space
  float available = get_metric(this);
  size_t num_fill_cells = 0;
  for (auto it = _cells.begin(); it != _cells.end(); ++it) {
    if ((*it).mode == CM_fill)
      ++num_fill_cells;
    else
      available -= get_metric((*it).node);
  }

  // Take spacing into account
  available -= max(0, _cells.size() - 1) * _spacing;

  if (available < 0.0f) {
    // luiBaseLayout_cat.warning() << "Not enough space available! (Missing " << -available << " pixels)" << endl;
    available = 0.0;
  }

  // Divide available space by amount of containers that specify the '*' flag
  available /= max(1, num_fill_cells);
  available = ceil(available);

  // cout << "Available metrics = " << ava%ilable << " (for " << num_fill_cells << " cells)" << endl;

  float this_metric = get_metric(this);
  float offset = 0.0;

  // Iterate over all cells and distribute them
  for (auto it = _cells.begin(); it != _cells.end(); ++it) {
    const Cell& cell = *it;
    set_offset(cell.node, offset);
    switch (cell.mode) {

      // Fixed metric
      case CM_fixed: {
        set_metric(cell.node, cell.payload);
        offset += cell.payload;
        break;
      }

      // Filler cell
      case CM_fill: {
        set_metric(cell.node, available);
        offset += available;
        break;
      }

      // Percentage
      case CM_percentage: {
        float pct_metric = this_metric * cell.payload;
        set_metric(cell.node, pct_metric);
        offset += pct_metric;
        break;
      }

      // Fit
      case CM_fit: {
        float cell_metric = get_metric(cell.node);
        offset += cell_metric;
        break;
      }

      default: {
        // Unkown metric type
        nassertv(false);
      }
    };
    offset += _spacing;
  }
}

void LUIBaseLayout::update_dimensions_upstream() {
  for (auto it = _children.begin(); it!= _children.end(); ++it) {
    (*it)->update_dimensions_upstream();
  }

  update_dimensions();
  update_layout();
  fit_dimensions();
}

void LUIBaseLayout::reset() {
  _cells.clear();
  remove_all_children();
}
<commit_msg>Fix unsigned/signed mismatch warning<commit_after>

#include "luiBaseLayout.h"

#include "pstrtod.h"
#include <sstream>

TypeHandle LUIBaseLayout::_type_handle;
NotifyCategoryDef(luiBaseLayout, ":lui");

LUIBaseLayout::LUIBaseLayout(PyObject* self) : LUIObject(self), _spacing(0.0f)
{
}

void LUIBaseLayout::add(PT(LUIBaseElement) object, const string& cell_mode) {
  if (object->has_parent()) {
    luiBaseLayout_cat.error() << "Cannot call add() with an object which already has a parent!" << endl;
    return;
  }

  add_cell(object, construct_cell(cell_mode));
}

void LUIBaseLayout::add(PT(LUIBaseElement) object, float cell_height) {
  Cell cell = { CM_fixed, cell_height, NULL };
  add_cell(object, cell);
}

LUIObject* LUIBaseLayout::add_cell(PT(LUIBaseElement) object, Cell cell) {
  // Construct cell container object
  LUIObject* container = new LUIObject(NULL);
  add_child(container);
  if (object)
    container->add_child(object);
  container->set_debug_name("LUILayoutCell");
  cell.node = container;
  init_container(container);
  _cells.push_back(cell);
  return container;
}

PT(LUIObject) LUIBaseLayout::cell(const string& cell_mode) {
  return add_cell(NULL, construct_cell(cell_mode));
}

PT(LUIObject) LUIBaseLayout::cell(float cell_height) {
  Cell cell = { CM_fixed, cell_height, NULL };
  return add_cell(NULL, cell);
}

PT(LUIObject) LUIBaseLayout::cell() {
  Cell cell = { CM_fit, 0.0f, NULL };
  return add_cell(NULL, cell);
}

bool check_int(const string& str) {
  for (auto it = str.begin(); it != str.end(); ++it) {
    if (*it < '0' || *it > '9')
      return false;
  }
  return true;
}

int parse_int(const string& str) {
  // Assumes valid int
  int result = 0;
  istringstream( str ) >> result;
  return result;
}

LUIBaseLayout::Cell LUIBaseLayout::construct_cell(const string& cell_mode) {
  Cell cell = { CM_fit, 0.0f, NULL };

  // Fit
  if (cell_mode == "?") {
    cell.mode = CM_fit;
    return cell;
  }

  // Fill
  if (cell_mode == "*") {
    cell.mode = CM_fill;
    return cell;
  }

  // Percentage
  if (cell_mode.back() == '%') {
    cell.mode = CM_percentage;

    // Parse payload
    string val = cell_mode.substr(0, cell_mode.size() - 1);
    char* endptr;
    double d_val = pstrtod(val.c_str(), &endptr);

    if (*endptr != 0) {
      luiBaseLayout_cat.error() << "Could not parse float: '" << val << "'" << endl;
      d_val = 0.0;
    }
    cell.payload = (float)(d_val / 100.0);
    return cell;
  }

  // Assume pixels otherwise
  if (check_int(cell_mode)) {
    cell.mode = CM_fixed;
    cell.payload = parse_int(cell_mode);
    return cell;
  }

  luiBaseLayout_cat.error() << "Invalid cell mode: '" << cell_mode << "'" << endl;
  return cell;
}

void LUIBaseLayout::update_layout() {
  // First, get available space
  float available = get_metric(this);
  size_t num_fill_cells = 0;
  for (auto it = _cells.begin(); it != _cells.end(); ++it) {
    if ((*it).mode == CM_fill)
      ++num_fill_cells;
    else
      available -= get_metric((*it).node);
  }

  // Take spacing into account
  available -= max(size_t(0), _cells.size() - 1) * _spacing;

  if (available < 0.0f) {
    // luiBaseLayout_cat.warning() << "Not enough space available! (Missing " << -available << " pixels)" << endl;
    available = 0.0;
  }

  // Divide available space by amount of containers that specify the '*' flag
  available /= max(size_t(1), num_fill_cells);
  available = ceil(available);

  // cout << "Available metrics = " << ava%ilable << " (for " << num_fill_cells << " cells)" << endl;

  float this_metric = get_metric(this);
  float offset = 0.0;

  // Iterate over all cells and distribute them
  for (auto it = _cells.begin(); it != _cells.end(); ++it) {
    const Cell& cell = *it;
    set_offset(cell.node, offset);
    switch (cell.mode) {

      // Fixed metric
      case CM_fixed: {
        set_metric(cell.node, cell.payload);
        offset += cell.payload;
        break;
      }

      // Filler cell
      case CM_fill: {
        set_metric(cell.node, available);
        offset += available;
        break;
      }

      // Percentage
      case CM_percentage: {
        float pct_metric = this_metric * cell.payload;
        set_metric(cell.node, pct_metric);
        offset += pct_metric;
        break;
      }

      // Fit
      case CM_fit: {
        float cell_metric = get_metric(cell.node);
        offset += cell_metric;
        break;
      }

      default: {
        // Unkown metric type
        nassertv(false);
      }
    };
    offset += _spacing;
  }
}

void LUIBaseLayout::update_dimensions_upstream() {
  for (auto it = _children.begin(); it!= _children.end(); ++it) {
    (*it)->update_dimensions_upstream();
  }

  update_dimensions();
  update_layout();
  fit_dimensions();
}

void LUIBaseLayout::reset() {
  _cells.clear();
  remove_all_children();
}
<|endoftext|>


<commit_before>/*
 * File:   IntervalManager.cpp
 * Author: etudiant
 *
 * Created on 2 juin 2014, 09:35
 */

#include "IntervalManager.h"

#include "../../utils.h"

int IntervalManager::INTERVAL_STEP = 2;

IntervalManager::IntervalManager(Strategy* strategy, Relation* relation) :
        strategy(strategy),
        relation(relation),
        dimension(-1),
        startedCSVOutput(false)
{}

IntervalManager::IntervalManager(const IntervalManager& orig) :
        strategy(orig.strategy),
        relation(orig.relation),
        intervals(orig.intervals),
        dimension(orig.dimension),
        startedCSVOutput(orig.startedCSVOutput)
{}

IntervalManager::~IntervalManager() {
}

const std::list<Interval*>& IntervalManager::getIntervals() const {
    return intervals;
}

const Relation* IntervalManager::getRelation() const {
    return relation;
}

void IntervalManager::setRelation(Relation* relation) {
    this->relation = relation;
}

const Strategy* IntervalManager::getStrategy() const {
    return strategy;
}

void IntervalManager::setStrategy(Strategy* strategy) {
    this->strategy = strategy;
}

void IntervalManager::prepareIntervals(int dimension, IntervalType type) {
    this->dimension = dimension;
    int min = 1;
    int max = INTERVAL_STEP;
    Interval* prev = NULL;
    while (min < dimension) {
        if (max > dimension) {
            max = dimension + 1;
        }

        if (prev != NULL
                && (max - min) < prev->getMaxDistance() - prev->getMinDistance()) {
            prev->setMaxDistance(prev->getMaxDistance() + (max - min));
            PRINTLN("IntervalManager: expanding last Interval: ["
                    << prev->getMinDistance() << "; "
                    << prev->getMaxDistance() << "[");
        } else {
            switch (type) {
                case DISJOINT:
                    // nuthin special
                    break;
                case JOINED_AT_ORIGIN:
                    min = 1;
                    break;
            }
            PRINTLN("IntervalManager: new Interval: [" << min << "; "
                << max << "[");
            Interval* interval = new Interval(min, max);
            intervals.push_back(interval);
            prev = interval;
        }

        min = max;
        max *= INTERVAL_STEP;
    }
}

void IntervalManager::memorizeAction(std::pair<int, int>& pair, int costDiff) {
    int distance = pair.second - pair.first;
    // if we go all the way around
    if (distance < 0) {
        distance = dimension - pair.second + pair.first;
    }
    //PRINTLN("distance="<<distance);
    for (Interval* interval : intervals) {
        if (distance < interval->getMaxDistance()
                && distance >= interval->getMinDistance()) {
            Action* action = new Action(pair, costDiff);
            interval->addAction(action);
        }
        // Note: don't break, more than one interval might qualify
    }
}

std::ostream& IntervalManager::outputDataCSV(std::ostream& out) {
    // prefix
    out << relation->getType() << "," << strategy->getType() << ",";
    // either 1st line data or current data
    if (!startedCSVOutput) {
        startedCSVOutput = true;
        for (Interval* interval : intervals) {
            out << "[" << interval->getMinDistance() << ";"
                    << interval->getMaxDistance() << "[,";
        }
    } else {
        for (Interval* interval : intervals) {
            out << interval->getActions().size() << ",";
        }
    }
    out << std::endl;

    return out;
}

std::ostream& operator<<(std::ostream& out, const IntervalManager& manager) {
    out << "IntervalManager: " << manager.getRelation()->getType()
            << " - " << manager.getStrategy()->getType();
    for (Interval* interval : manager.getIntervals()) {
        out << "\n\t" << interval;
    }
    return out;
}

std::ostream& operator<<(std::ostream& out, const IntervalManager* manager) {
    out << *manager;
    return out;
}<commit_msg>Interval step default value restored to 4<commit_after>/*
 * File:   IntervalManager.cpp
 * Author: etudiant
 *
 * Created on 2 juin 2014, 09:35
 */

#include "IntervalManager.h"

#include "../../utils.h"

int IntervalManager::INTERVAL_STEP = 4;

IntervalManager::IntervalManager(Strategy* strategy, Relation* relation) :
        strategy(strategy),
        relation(relation),
        dimension(-1),
        startedCSVOutput(false)
{}

IntervalManager::IntervalManager(const IntervalManager& orig) :
        strategy(orig.strategy),
        relation(orig.relation),
        intervals(orig.intervals),
        dimension(orig.dimension),
        startedCSVOutput(orig.startedCSVOutput)
{}

IntervalManager::~IntervalManager() {
}

const std::list<Interval*>& IntervalManager::getIntervals() const {
    return intervals;
}

const Relation* IntervalManager::getRelation() const {
    return relation;
}

void IntervalManager::setRelation(Relation* relation) {
    this->relation = relation;
}

const Strategy* IntervalManager::getStrategy() const {
    return strategy;
}

void IntervalManager::setStrategy(Strategy* strategy) {
    this->strategy = strategy;
}

void IntervalManager::prepareIntervals(int dimension, IntervalType type) {
    this->dimension = dimension;
    int min = 1;
    int max = INTERVAL_STEP;
    Interval* prev = NULL;
    while (min < dimension) {
        if (max > dimension) {
            max = dimension + 1;
        }

        if (prev != NULL
                && (max - min) < prev->getMaxDistance() - prev->getMinDistance()) {
            prev->setMaxDistance(prev->getMaxDistance() + (max - min));
            PRINTLN("IntervalManager: expanding last Interval: ["
                    << prev->getMinDistance() << "; "
                    << prev->getMaxDistance() << "[");
        } else {
            switch (type) {
                case DISJOINT:
                    // nuthin special
                    break;
                case JOINED_AT_ORIGIN:
                    min = 1;
                    break;
            }
            PRINTLN("IntervalManager: new Interval: [" << min << "; "
                << max << "[");
            Interval* interval = new Interval(min, max);
            intervals.push_back(interval);
            prev = interval;
        }

        min = max;
        max *= INTERVAL_STEP;
    }
}

void IntervalManager::memorizeAction(std::pair<int, int>& pair, int costDiff) {
    int distance = pair.second - pair.first;
    // if we go all the way around
    if (distance < 0) {
        distance = dimension - pair.second + pair.first;
    }
    //PRINTLN("distance="<<distance);
    for (Interval* interval : intervals) {
        if (distance < interval->getMaxDistance()
                && distance >= interval->getMinDistance()) {
            Action* action = new Action(pair, costDiff);
            interval->addAction(action);
        }
        // Note: don't break, more than one interval might qualify
    }
}

std::ostream& IntervalManager::outputDataCSV(std::ostream& out) {
    // prefix
    out << relation->getType() << "," << strategy->getType() << ",";
    // either 1st line data or current data
    if (!startedCSVOutput) {
        startedCSVOutput = true;
        for (Interval* interval : intervals) {
            out << "[" << interval->getMinDistance() << ";"
                    << interval->getMaxDistance() << "[,";
        }
    } else {
        for (Interval* interval : intervals) {
            out << interval->getActions().size() << ",";
        }
    }
    out << std::endl;

    return out;
}

std::ostream& operator<<(std::ostream& out, const IntervalManager& manager) {
    out << "IntervalManager: " << manager.getRelation()->getType()
            << " - " << manager.getStrategy()->getType();
    for (Interval* interval : manager.getIntervals()) {
        out << "\n\t" << interval;
    }
    return out;
}

std::ostream& operator<<(std::ostream& out, const IntervalManager* manager) {
    out << *manager;
    return out;
}<|endoftext|>


<commit_before>//
//  MCLibetpan.cpp
//  mailcore2
//
//  Created by Hoa Dinh on 6/28/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCLibetpan.h"

#include <libetpan/libetpan.h>

__attribute__((constructor))
static void initialize() {
    mailstream_cfstream_enabled = 1;
}
<commit_msg>Added a comment about mailstream_cfstream_enabled.<commit_after>//
//  MCLibetpan.cpp
//  mailcore2
//
//  Created by Hoa Dinh on 6/28/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCLibetpan.h"

#include <libetpan/libetpan.h>

__attribute__((constructor))
static void initialize() {
    // It will enable CFStream on platforms that supports it.
    mailstream_cfstream_enabled = 1;
}
<|endoftext|>


<commit_before>/**************************************************************************\
 * lines, circles, ...                                                    *
 *                                               ___                      *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___     *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|    *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \    *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/    *
 *                |___/                              |_|                  *
 *                                                                        *
 * Copyright (c) 2014 Florian Oetke                                       *
 *  Based on code of GDW-SS2014 project by Stefan Bodenschatz             *
 *  which was distributed under the MIT license.                          *
 *                                                                        *
 *  This file is part of MagnumOpus and distributed under the MIT License *
 *  See LICENSE file for details.                                         *
\**************************************************************************/

#pragma once

#include "../units.hpp"
#include "shader.hpp"
#include "vertex_object.hpp"
#include "texture.hpp"

namespace mo {
namespace renderer {

	class Texture;

	struct Simple_vertex {
		glm::vec2 xy;
		glm::vec2 uv;
		Simple_vertex(glm::vec2 xy, glm::vec2 uv) : xy(xy), uv(uv) {}
	};
	extern Vertex_layout simple_vertex_layout;

	class Ray_renderer {
		public:
			Ray_renderer(asset::Asset_manager& assets);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec3 p, Angle a, float length, glm::vec4 color, float width=1);

		private:
			Shader_program _prog;
			Object _obj;
	};

	class Bubble_renderer {
		public:
			Bubble_renderer(asset::Asset_manager& assets, float radius);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec2 center, float fill_level, float activity, float time, const Texture& texture);

			void draw_glow(glm::vec2 center, float fill_level, float activity, float time, const Texture& texture);

		private:
			const float _radius;
			Shader_program _prog;
			Object _obj;
	};

	class Textured_box {
		public:
			Textured_box(asset::Asset_manager& assets, asset::AID tex, int width = 100, int height = 100);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec2 center);

		private:
			Shader_program _prog;
			Object _obj;
			Texture_ptr _texture;

	};

	class Textured_box {
		public:
			Textured_box(asset::Asset_manager& assets, asset::AID tex, int width = 100, int height = 100);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec2 center);

		private:
			Shader_program _prog;
			Object _obj;
			Texture_ptr _texture;

	};

}
}
<commit_msg>hopefully fixed the merge/rebase issues<commit_after>/**************************************************************************\
 * lines, circles, ...                                                    *
 *                                               ___                      *
 *    /\/\   __ _  __ _ _ __  _   _ _ __ ___     /___\_ __  _   _ ___     *
 *   /    \ / _` |/ _` | '_ \| | | | '_ ` _ \   //  // '_ \| | | / __|    *
 *  / /\/\ \ (_| | (_| | | | | |_| | | | | | | / \_//| |_) | |_| \__ \    *
 *  \/    \/\__,_|\__, |_| |_|\__,_|_| |_| |_| \___/ | .__/ \__,_|___/    *
 *                |___/                              |_|                  *
 *                                                                        *
 * Copyright (c) 2014 Florian Oetke                                       *
 *  Based on code of GDW-SS2014 project by Stefan Bodenschatz             *
 *  which was distributed under the MIT license.                          *
 *                                                                        *
 *  This file is part of MagnumOpus and distributed under the MIT License *
 *  See LICENSE file for details.                                         *
\**************************************************************************/

#pragma once

#include "../units.hpp"
#include "shader.hpp"
#include "vertex_object.hpp"
#include "texture.hpp"

namespace mo {
namespace renderer {

	class Texture;

	struct Simple_vertex {
		glm::vec2 xy;
		glm::vec2 uv;
		Simple_vertex(glm::vec2 xy, glm::vec2 uv) : xy(xy), uv(uv) {}
	};
	extern Vertex_layout simple_vertex_layout;

	class Ray_renderer {
		public:
			Ray_renderer(asset::Asset_manager& assets);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec3 p, Angle a, float length, glm::vec4 color, float width=1);

		private:
			Shader_program _prog;
			Object _obj;
	};

	class Bubble_renderer {
		public:
			Bubble_renderer(asset::Asset_manager& assets, float radius);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec2 center, float fill_level, float activity, float time, const Texture& texture);

			void draw_glow(glm::vec2 center, float fill_level, float activity, float time, const Texture& texture);

		private:
			const float _radius;
			Shader_program _prog;
			Object _obj;
	};

	class Textured_box {
		public:
			Textured_box(asset::Asset_manager& assets, asset::AID tex, int width = 100, int height = 100);

			void set_vp(const glm::mat4& vp);

			void draw(glm::vec2 center);

		private:
			Shader_program _prog;
			Object _obj;
			Texture_ptr _texture;

	};

}
}
<|endoftext|>


<commit_before>#include "../../../Units/Units.h"
#include "../../../Node/Node.h"
#include "../../../ParseResult/ParseResult.h"
#include "../../../Function/Function.h"
#include "../../../Operation/Destruct/Destruct.h"
#include "../../../Operation/Copy/Copy.h"
#include "../Inst/Inst.h"
#include "../../Utils/Utils.h"
#include "../../../llvm_Function.h"

using namespace dale::ErrorInst;

namespace dale
{
bool
destructTwo(Context *ctx, ParseResult *one, ParseResult *two,
            ParseResult *three, llvm::IRBuilder<> *builder)
{
    one->block = two->block;
    bool res = Operation::Destruct(ctx, one, three, builder);
    if (!res) {
        return false;
    }
    two->block = three->block;
    res = Operation::Destruct(ctx, two, three, builder);
    if (!res) {
        return false;
    }
    return true;
}

Function *
getCopyAssign(Context *ctx, Type *dst_type, Type *src_type)
{
    std::vector<Type *> types;
    types.push_back(dst_type);
    types.push_back(src_type);
    return ctx->getFunction("setf-copy-assign", &types, NULL, false);
}

bool
processCopyPtrCall(Context *ctx, Function *over_setf,
                   llvm::IRBuilder<> *builder,
                   ParseResult *variable_pr, ParseResult *value_pr,
                   ParseResult *pr)
{
    llvm::Value *src_ptr =
        llvm::cast<llvm::Value>(
            builder->CreateAlloca(
                ctx->toLLVMType(value_pr->type, NULL, false, false)
            )
        );
    builder->CreateStore(value_pr->value, src_ptr);

    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(src_ptr);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    ParseResult destruct_pr;
    bool res = destructTwo(ctx, variable_pr, value_pr, &destruct_pr, builder);
    if (!res) {
        return false;
    }

    pr->set(destruct_pr.block, ctx->tr->type_bool, ret);
    return true;
}

bool
processCopyExactCall(Context *ctx, Function *over_setf,
                     llvm::IRBuilder<> *builder,
                     ParseResult *variable_pr, ParseResult *value_pr,
                     ParseResult *pr)
{
    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(value_pr->value);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    ParseResult destruct_pr;
    bool res = destructTwo(ctx, variable_pr, value_pr, &destruct_pr, builder);
    if (!res) {
        return false;
    }

    pr->set(destruct_pr.block, ctx->tr->type_bool, ret);
    return true;
}

Function *
getMoveAssign(Context *ctx, Type *dst_type, Type *src_type)
{
    std::vector<Type *> types;
    types.push_back(dst_type);
    types.push_back(src_type);
    std::vector<bool> lvalues;
    lvalues.push_back(true);
    lvalues.push_back(false);
    return ctx->getFunction("setf-move-assign", &types, NULL, false,
                            &lvalues);
}

bool
processMovePtrCall(Context *ctx, Function *over_setf,
                   llvm::IRBuilder<> *builder,
                   ParseResult *variable_pr, ParseResult *value_pr,
                   ParseResult *pr)
{
    ParseResult value_ptr_pr;
    bool res = value_pr->getAddressOfValue(ctx, &value_ptr_pr);
    if (!res) {
        return false;
    }

    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(value_ptr_pr.value);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    res = Operation::Destruct(ctx, variable_pr, pr, builder);
    if (!res) {
        return false;
    }

    pr->set(pr->block, ctx->tr->type_bool, ret);
    return true;
}

bool
FormProcSetfParse(Units *units, Function *fn, llvm::BasicBlock *block,
                  Node *node, bool get_address, bool prefixed_with_core,
                  ParseResult *pr)
{
    Context *ctx = units->top()->ctx;

    std::vector<Node *> *lst = node->list;

    if (!ctx->er->assertArgNums("setf", node, 2, 2)) {
        return false;
    }

    ParseResult variable_pr;
    bool res =
        FormProcInstParse(units, fn, block, (*lst)[1], false,
                          false, NULL, &variable_pr);
    if (!res) {
        return false;
    }

    if (!variable_pr.type->points_to) {
        Error *e = new Error(IncorrectArgType, (*lst)[1],
                             "setf", "a pointer", "1", "a value");
        ctx->er->addError(e);
        return false;
    }

    if (variable_pr.type->points_to->is_const) {
        Error *e = new Error(CannotModifyConstVariable, node);
        ctx->er->addError(e);
        return false;
    }

    Node *value_node = (*lst)[2];
    value_node = units->top()->mp->parsePotentialMacroCall(value_node);
    if (!value_node) {
        return false;
    }

    llvm::IRBuilder<> builder(variable_pr.block);
    ParseResult value_pr;
    value_pr.retval = variable_pr.value;
    value_pr.retval_type = variable_pr.type;

    res = FormProcInstParse(units, fn, block, value_node, get_address,
                            false, variable_pr.type->points_to,
                            &value_pr);
    if (!res) {
        return false;
    }
    if (value_pr.retval_used) {
        pr->block = value_pr.block;
        pr->type = ctx->tr->getBasicType(BaseType::Void);
        return true;
    }

    builder.SetInsertPoint(value_pr.block);

    if (!prefixed_with_core) {
        Function *over_setf = getMoveAssign(ctx, variable_pr.type,
                                            value_pr.type);
        if (over_setf && !value_pr.value_is_lvalue) {
            return processMovePtrCall(ctx, over_setf, &builder,
                                      &variable_pr, &value_pr, pr);
        }
    }

    if (!Operation::IsCopyPermitted(ctx, node, variable_pr.type->points_to)) {
        return false;
    }

    /* If an overridden setf exists, and value_pr is a value of the
     * pointee type of variable_pr, then call the overridden setf
     * after allocating memory for value_pr and copying it into place.
     * */

    if (!prefixed_with_core
            && variable_pr.type->points_to->canBeSetFrom(value_pr.type)) {
        Function *over_setf = getCopyAssign(ctx, variable_pr.type,
                                            variable_pr.type);
        if (over_setf) {
            return processCopyPtrCall(ctx, over_setf, &builder,
                                      &variable_pr, &value_pr, pr);
        }
    }

    /* If an appropriate setf definition exists, which matches
     * the arguments exactly, then use it. */

    if (!prefixed_with_core) {
        Function *over_setf = getCopyAssign(ctx, variable_pr.type,
                                            value_pr.type);
        if (over_setf) {
            return processCopyExactCall(ctx, over_setf, &builder,
                                        &variable_pr, &value_pr, pr);
        }
    }

    if (variable_pr.type->points_to->canBeSetFrom(value_pr.type)) {
        builder.CreateStore(value_pr.value, variable_pr.value);

        ParseResult destruct_pr;
        bool res = destructTwo(ctx, &variable_pr, &value_pr,
                               &destruct_pr, &builder);
        if (!res) {
            return false;
        }

        pr->set(destruct_pr.block, ctx->tr->type_bool,
                ctx->nt->getLLVMTrue());
        pr->do_not_copy_with_setf = true;
        return true;
    }

    /* This is used to set an error message. */
    ctx->er->assertTypeEquality("setf", (*lst)[2],
                                value_pr.type,
                                variable_pr.type->points_to,
                                false);
    return false;
}
}
<commit_msg>[master] do not try to parse setf values as macro calls (#93)<commit_after>#include "../../../Units/Units.h"
#include "../../../Node/Node.h"
#include "../../../ParseResult/ParseResult.h"
#include "../../../Function/Function.h"
#include "../../../Operation/Destruct/Destruct.h"
#include "../../../Operation/Copy/Copy.h"
#include "../Inst/Inst.h"
#include "../../Utils/Utils.h"
#include "../../../llvm_Function.h"

using namespace dale::ErrorInst;

namespace dale
{
bool
destructTwo(Context *ctx, ParseResult *one, ParseResult *two,
            ParseResult *three, llvm::IRBuilder<> *builder)
{
    one->block = two->block;
    bool res = Operation::Destruct(ctx, one, three, builder);
    if (!res) {
        return false;
    }
    two->block = three->block;
    res = Operation::Destruct(ctx, two, three, builder);
    if (!res) {
        return false;
    }
    return true;
}

Function *
getCopyAssign(Context *ctx, Type *dst_type, Type *src_type)
{
    std::vector<Type *> types;
    types.push_back(dst_type);
    types.push_back(src_type);
    return ctx->getFunction("setf-copy-assign", &types, NULL, false);
}

bool
processCopyPtrCall(Context *ctx, Function *over_setf,
                   llvm::IRBuilder<> *builder,
                   ParseResult *variable_pr, ParseResult *value_pr,
                   ParseResult *pr)
{
    llvm::Value *src_ptr =
        llvm::cast<llvm::Value>(
            builder->CreateAlloca(
                ctx->toLLVMType(value_pr->type, NULL, false, false)
            )
        );
    builder->CreateStore(value_pr->value, src_ptr);

    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(src_ptr);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    ParseResult destruct_pr;
    bool res = destructTwo(ctx, variable_pr, value_pr, &destruct_pr, builder);
    if (!res) {
        return false;
    }

    pr->set(destruct_pr.block, ctx->tr->type_bool, ret);
    return true;
}

bool
processCopyExactCall(Context *ctx, Function *over_setf,
                     llvm::IRBuilder<> *builder,
                     ParseResult *variable_pr, ParseResult *value_pr,
                     ParseResult *pr)
{
    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(value_pr->value);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    ParseResult destruct_pr;
    bool res = destructTwo(ctx, variable_pr, value_pr, &destruct_pr, builder);
    if (!res) {
        return false;
    }

    pr->set(destruct_pr.block, ctx->tr->type_bool, ret);
    return true;
}

Function *
getMoveAssign(Context *ctx, Type *dst_type, Type *src_type)
{
    std::vector<Type *> types;
    types.push_back(dst_type);
    types.push_back(src_type);
    std::vector<bool> lvalues;
    lvalues.push_back(true);
    lvalues.push_back(false);
    return ctx->getFunction("setf-move-assign", &types, NULL, false,
                            &lvalues);
}

bool
processMovePtrCall(Context *ctx, Function *over_setf,
                   llvm::IRBuilder<> *builder,
                   ParseResult *variable_pr, ParseResult *value_pr,
                   ParseResult *pr)
{
    ParseResult value_ptr_pr;
    bool res = value_pr->getAddressOfValue(ctx, &value_ptr_pr);
    if (!res) {
        return false;
    }

    std::vector<llvm::Value *> call_args;
    call_args.push_back(variable_pr->value);
    call_args.push_back(value_ptr_pr.value);
    llvm::Value *ret =
        builder->CreateCall(over_setf->llvm_function,
                            llvm::ArrayRef<llvm::Value*>(call_args));

    res = Operation::Destruct(ctx, variable_pr, pr, builder);
    if (!res) {
        return false;
    }

    pr->set(pr->block, ctx->tr->type_bool, ret);
    return true;
}

bool
FormProcSetfParse(Units *units, Function *fn, llvm::BasicBlock *block,
                  Node *node, bool get_address, bool prefixed_with_core,
                  ParseResult *pr)
{
    Context *ctx = units->top()->ctx;

    std::vector<Node *> *lst = node->list;

    if (!ctx->er->assertArgNums("setf", node, 2, 2)) {
        return false;
    }

    ParseResult variable_pr;
    bool res =
        FormProcInstParse(units, fn, block, (*lst)[1], false,
                          false, NULL, &variable_pr);
    if (!res) {
        return false;
    }

    if (!variable_pr.type->points_to) {
        Error *e = new Error(IncorrectArgType, (*lst)[1],
                             "setf", "a pointer", "1", "a value");
        ctx->er->addError(e);
        return false;
    }

    if (variable_pr.type->points_to->is_const) {
        Error *e = new Error(CannotModifyConstVariable, node);
        ctx->er->addError(e);
        return false;
    }

    Node *value_node = (*lst)[2];
    llvm::IRBuilder<> builder(variable_pr.block);
    ParseResult value_pr;
    value_pr.retval = variable_pr.value;
    value_pr.retval_type = variable_pr.type;

    res = FormProcInstParse(units, fn, block, value_node, get_address,
                            false, variable_pr.type->points_to,
                            &value_pr);
    if (!res) {
        return false;
    }
    if (value_pr.retval_used) {
        pr->block = value_pr.block;
        pr->type = ctx->tr->getBasicType(BaseType::Void);
        return true;
    }

    builder.SetInsertPoint(value_pr.block);

    if (!prefixed_with_core) {
        Function *over_setf = getMoveAssign(ctx, variable_pr.type,
                                            value_pr.type);
        if (over_setf && !value_pr.value_is_lvalue) {
            return processMovePtrCall(ctx, over_setf, &builder,
                                      &variable_pr, &value_pr, pr);
        }
    }

    if (!Operation::IsCopyPermitted(ctx, node, variable_pr.type->points_to)) {
        return false;
    }

    /* If an overridden setf exists, and value_pr is a value of the
     * pointee type of variable_pr, then call the overridden setf
     * after allocating memory for value_pr and copying it into place.
     * */

    if (!prefixed_with_core
            && variable_pr.type->points_to->canBeSetFrom(value_pr.type)) {
        Function *over_setf = getCopyAssign(ctx, variable_pr.type,
                                            variable_pr.type);
        if (over_setf) {
            return processCopyPtrCall(ctx, over_setf, &builder,
                                      &variable_pr, &value_pr, pr);
        }
    }

    /* If an appropriate setf definition exists, which matches
     * the arguments exactly, then use it. */

    if (!prefixed_with_core) {
        Function *over_setf = getCopyAssign(ctx, variable_pr.type,
                                            value_pr.type);
        if (over_setf) {
            return processCopyExactCall(ctx, over_setf, &builder,
                                        &variable_pr, &value_pr, pr);
        }
    }

    if (variable_pr.type->points_to->canBeSetFrom(value_pr.type)) {
        builder.CreateStore(value_pr.value, variable_pr.value);

        ParseResult destruct_pr;
        bool res = destructTwo(ctx, &variable_pr, &value_pr,
                               &destruct_pr, &builder);
        if (!res) {
            return false;
        }

        pr->set(destruct_pr.block, ctx->tr->type_bool,
                ctx->nt->getLLVMTrue());
        pr->do_not_copy_with_setf = true;
        return true;
    }

    /* This is used to set an error message. */
    ctx->er->assertTypeEquality("setf", (*lst)[2],
                                value_pr.type,
                                variable_pr.type->points_to,
                                false);
    return false;
}
}
<|endoftext|>