<commit_before>
//
// Copyright (c) 2012 Jonathan Topf
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#if defined __APPLE__
#include <maya/OpenMayaMac.h>
#endif

#include <maya/MIOStream.h>
#include <maya/MSimple.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MSelectionList.h>
#include <maya/MFnMesh.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MPointArray.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MArgList.h>
#include <maya/MString.h>
#include <fstream>

const MString Version("0.1.1");

DeclareSimpleCommand(ms_export_obj, "mayaseed", Version.asChar());

MStatus ms_export_obj::doIt(const MArgList& args)
{
    // Get the args.
    MString mesh_name;
    MString file_path;
    for (unsigned int i = 0; i < args.length(); i++)
    {
        MGlobal::displayInfo(args.asString(i));
        if (args.asString(i) == "-mesh")
        {
            mesh_name = args.asString(i+1);
        }
        else if (args.asString(i) == "-filePath")
        {
            file_path = args.asString(i+1);
        }
    }

    MString display_info;
    display_info.format("Exporting ^1s using ms_export_obj", mesh_name);
    MGlobal::displayInfo(display_info);

    MSelectionList sel;
    sel.add(mesh_name);
    MDagPath mesh_dag_path;
    sel.getDagPath(0, mesh_dag_path);

    MFnMesh mesh(mesh_dag_path);
    MItMeshPolygon iter_polys(mesh.object());

    // Open file for writing, overwriting previous contents.
    std::ofstream out_file;
    out_file.open(file_path.asChar(), ios::trunc);
    out_file << "# File generated by ms_export_obj version " << Version.asChar() << "\n\n";

    // Write vertices.
    MPointArray point_array;
    mesh.getPoints(point_array);
    for (unsigned int i = 0; i < point_array.length(); i++)
    {
        const MPoint& p = point_array[i];
        out_file << "v " << p.x << " " << p.y << " " << p.z << "\n";
    }

    // Write UVs.
    MFloatArray u_array;
    MFloatArray v_array;
    mesh.getUVs(u_array, v_array);
    for (unsigned int i = 0; i < u_array.length(); i++)
    {
        out_file << "vt " << u_array[i] << " " << v_array[i] << "\n";
    }

    // Write normals.
    MFloatVectorArray normal_array;
    mesh.getNormals(normal_array, MSpace::kTransform);
    for (unsigned int i = 0; i < normal_array.length(); i++)
    {
        const MFloatVector& n = normal_array[i];
        out_file << "vn " << n.x << " " << n.y <<  " " << n.z << "\n";
    }

    // Write polys.
    while (!iter_polys.isDone())
    {
        out_file << "f ";

        unsigned int vert_count = iter_polys.polygonVertexCount();
        for (unsigned int i = 0; i < vert_count; i++)
        {
            int uv_index;
            iter_polys.getUVIndex(i, uv_index);
            out_file << (iter_polys.vertexIndex(i) + 1) << "/" << (uv_index + 1) << "/" << (iter_polys.normalIndex(i) + 1) << " ";
        }

        out_file << "\n";

        iter_polys.next();
    }

    out_file.close();

    return MS::kSuccess;
}
<commit_msg>removed debug output.<commit_after>
//
// Copyright (c) 2012 Jonathan Topf
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#if defined __APPLE__
#include <maya/OpenMayaMac.h>
#endif

#include <maya/MIOStream.h>
#include <maya/MSimple.h>
#include <maya/MGlobal.h>
#include <maya/MSelectionList.h>
#include <maya/MDagPath.h>
#include <maya/MSelectionList.h>
#include <maya/MFnMesh.h>
#include <maya/MItMeshPolygon.h>
#include <maya/MPointArray.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MArgList.h>
#include <maya/MString.h>
#include <fstream>

const MString Version("0.1.1");

DeclareSimpleCommand(ms_export_obj, "mayaseed", Version.asChar());

MStatus ms_export_obj::doIt(const MArgList& args)
{
    // Get the args.
    MString mesh_name;
    MString file_path;
    for (unsigned int i = 0; i < args.length(); i++)
    {
        if (args.asString(i) == "-mesh")
            mesh_name = args.asString(i+1);
        else if (args.asString(i) == "-filePath")
            file_path = args.asString(i+1);
    }

    MString display_info;
    display_info.format("Exporting ^1s using ms_export_obj", mesh_name);
    MGlobal::displayInfo(display_info);

    MSelectionList sel;
    sel.add(mesh_name);
    MDagPath mesh_dag_path;
    sel.getDagPath(0, mesh_dag_path);

    MFnMesh mesh(mesh_dag_path);
    MItMeshPolygon iter_polys(mesh.object());

    // Open file for writing, overwriting previous contents.
    std::ofstream out_file;
    out_file.open(file_path.asChar(), ios::trunc);
    out_file << "# File generated by ms_export_obj version " << Version.asChar() << "\n\n";

    // Write vertices.
    MPointArray point_array;
    mesh.getPoints(point_array);
    for (unsigned int i = 0; i < point_array.length(); i++)
    {
        const MPoint& p = point_array[i];
        out_file << "v " << p.x << " " << p.y << " " << p.z << "\n";
    }

    // Write UVs.
    MFloatArray u_array;
    MFloatArray v_array;
    mesh.getUVs(u_array, v_array);
    for (unsigned int i = 0; i < u_array.length(); i++)
    {
        out_file << "vt " << u_array[i] << " " << v_array[i] << "\n";
    }

    // Write normals.
    MFloatVectorArray normal_array;
    mesh.getNormals(normal_array, MSpace::kTransform);
    for (unsigned int i = 0; i < normal_array.length(); i++)
    {
        const MFloatVector& n = normal_array[i];
        out_file << "vn " << n.x << " " << n.y <<  " " << n.z << "\n";
    }

    // Write polys.
    while (!iter_polys.isDone())
    {
        out_file << "f ";

        unsigned int vert_count = iter_polys.polygonVertexCount();
        for (unsigned int i = 0; i < vert_count; i++)
        {
            int uv_index;
            iter_polys.getUVIndex(i, uv_index);
            out_file << (iter_polys.vertexIndex(i) + 1) << "/" << (uv_index + 1) << "/" << (iter_polys.normalIndex(i) + 1) << " ";
        }

        out_file << "\n";

        iter_polys.next();
    }

    out_file.close();

    return MS::kSuccess;
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <QApplication>

#include "CodeExamples.h"
#include "CodeViewer/Dialog.h"
#include "SyntaxHighlighter/Cpp.h"

class DummyCodeReport : public CodeReport {
 public:
  explicit DummyCodeReport(uint32_t num_samples) : num_samples_{num_samples} {}

  [[nodiscard]] uint32_t GetNumSamplesInFunction() const override { return num_samples_; }
  [[nodiscard]] uint32_t GetNumSamples() const override { return num_samples_; }
  [[nodiscard]] std::optional<uint32_t> GetNumSamplesAtLine(size_t line) const override {
    return line;
  }

 private:
  uint32_t num_samples_ = 0;
};

int main(int argc, char* argv[]) {
  QApplication app{argc, argv};

  orbit_code_viewer::Dialog dialog{};

  // Example file
  const QString content = testing_example;

  dialog.SetMainContent(content, std::make_unique<orbit_syntax_highlighter::Cpp>());

  const auto line_numbers = content.count('\n');
  const DummyCodeReport code_report{static_cast<uint32_t>(line_numbers)};
  dialog.SetHeatmap(orbit_code_viewer::FontSizeInEm{1.2f}, &code_report);

  dialog.SetLineNumberTypes(orbit_code_viewer::Dialog::LineNumberTypes::kOnlyMainContent);
  dialog.SetEnableSampleCounters(true);
  dialog.GoToLineNumber(10);
  dialog.SetHighlightCurrentLine(true);

  return dialog.exec();
}<commit_msg>Integrate annotation into CodeViewerDemo<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <QApplication>

#include "CodeExamples.h"
#include "CodeViewer/Dialog.h"
#include "SyntaxHighlighter/X86Assembly.h"

class DummyCodeReport : public CodeReport {
 public:
  explicit DummyCodeReport(uint32_t num_samples) : num_samples_{num_samples} {}

  [[nodiscard]] uint32_t GetNumSamplesInFunction() const override { return num_samples_; }
  [[nodiscard]] uint32_t GetNumSamples() const override { return num_samples_; }
  [[nodiscard]] std::optional<uint32_t> GetNumSamplesAtLine(size_t line) const override {
    return line;
  }

 private:
  uint32_t num_samples_ = 0;
};

int main(int argc, char* argv[]) {
  QApplication app{argc, argv};

  orbit_code_viewer::Dialog dialog{};

  // Example file
  const QString content = x86Assembly_example;

  dialog.SetMainContent(content, std::make_unique<orbit_syntax_highlighter::X86Assembly>());

  std::vector<orbit_code_viewer::AnnotatingLine> lines{};
  lines.emplace_back();
  lines.back().reference_line = 9;
  lines.back().line_number = 42;
  lines.back().line_contents = "void main() {";

  lines.emplace_back();
  lines.back().reference_line = 14;
  lines.back().line_number = 43;
  lines.back().line_contents = "echo \"Hello World!\";";

  dialog.SetAnnotatingContent(lines);

  const auto line_numbers = content.count('\n');
  const DummyCodeReport code_report{static_cast<uint32_t>(line_numbers)};
  dialog.SetHeatmap(orbit_code_viewer::FontSizeInEm{1.2f}, &code_report);

  dialog.SetLineNumberTypes(orbit_code_viewer::Dialog::LineNumberTypes::kOnlyAnnotatingLines);
  dialog.SetEnableSampleCounters(true);
  dialog.GoToLineNumber(10);
  dialog.SetHighlightCurrentLine(true);

  return dialog.exec();
}<|endoftext|>


<commit_before>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh 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 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  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 Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh 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 LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  Implements the OpenMesh IOManager singleton
//
//=============================================================================

//== INCLUDES =================================================================

#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/IO/IOManager.hh>

//== NAMESPACES ===============================================================

namespace OpenMesh {
namespace IO {

//=============================================================================

_IOManager_  *__IOManager_instance = 0;

_IOManager_& IOManager()
{
  if (!__IOManager_instance)  __IOManager_instance = new _IOManager_();
  return *__IOManager_instance;
}

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

bool
_IOManager_::
read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
{
  std::set<BaseReader*>::const_iterator it     =  reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end =  reader_modules_.end();

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_read(_filename))
    {
      _bi.prepare();
      bool ok = (*it)->read(_filename, _bi, _opt);
      _bi.finish();
      return ok;
    }

  // All modules failed to read
  return false;
}

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

bool
_IOManager_::
read(std::istream& _is, const std::string& _ext, BaseImporter& _bi, Options& _opt)
{
  std::set<BaseReader*>::const_iterator it     =  reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end =  reader_modules_.end();

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->BaseReader::can_u_read(_ext))  //Use the extension check only (no file existence)
    {
      _bi.prepare();
      bool ok = (*it)->read(_is, _bi, _opt);
      _bi.finish();
      return ok;
    }

  // All modules failed to read
  return false;
}

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

bool
_IOManager_::
write(const std::string& _filename, BaseExporter& _be, Options _opt)
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();

  if ( it == it_end )
  {
    omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n";
    return false;
  }

  // Try all registered modules
  for(; it != it_end; ++it)
  {
    if ((*it)->can_u_write(_filename))
    {
      return (*it)->write(_filename, _be, _opt);
    }
  }

  // All modules failed to save
  return false;
}

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

bool
_IOManager_::
write(std::ostream& _os,const std::string &_ext, BaseExporter& _be, Options _opt)
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();

  if ( it == it_end )
  {
    omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n";
    return false;
  }

  // Try all registered modules
  for(; it != it_end; ++it)
  {
    if ((*it)->BaseWriter::can_u_write(_ext)) //Restrict test to the extension check
    {
      return (*it)->write(_os, _be, _opt);
    }
  }

  // All modules failed to save
  return false;
}

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

bool
_IOManager_::
can_read( const std::string& _format ) const
{
  std::set<BaseReader*>::const_iterator it     = reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end = reader_modules_.end();
  std::string filename = "dummy." + _format;

  for(; it != it_end; ++it)
    if ((*it)->can_u_read(filename))
      return true;

  return false;
}

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

bool
_IOManager_::
can_write( const std::string& _format ) const
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();
  std::string filename = "dummy." + _format;

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_write(filename))
      return true;

  return false;
}

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

const BaseWriter*
_IOManager_::
find_writer(const std::string& _format)
{
  using std::string;

  string::size_type dot = _format.rfind('.');

  string ext;
  if (dot == string::npos)
    ext = _format;
  else
    ext = _format.substr(dot+1,_format.length()-(dot+1));

  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();
  std::string filename = "dummy." + ext;

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_write(filename))
      return *it;

  return NULL;
}

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

void
_IOManager_::
update_read_filters()
{
  std::set<BaseReader*>::const_iterator it     = reader_modules_.begin(),
                                        it_end = reader_modules_.end();
  std::string s, all, filters;

  for(; it != it_end; ++it)
  {
    filters += (*it)->get_description() + " (";

    std::istringstream iss((*it)->get_extensions());
    while (iss && !iss.eof() && (iss >> s))
    { s = " *." + s; filters += s; all += s; }

    filters += " );;";
  }

  all = "All files ( " + all + " );;";

  read_filters_ = all + filters;
}

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

void
_IOManager_::
update_write_filters()
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin(),
                                        it_end = writer_modules_.end();
  std::string s, all, filters;

  for(; it != it_end; ++it)
  {
    filters += (*it)->get_description() + " (";

    std::istringstream iss((*it)->get_extensions());
    while (iss && !iss.eof() && (iss >> s))
    { s = " *." + s; filters += s; all += s; }

    filters += " );;";
  }
  all = "All files ( " + all + " );;";

  write_filters_ = all + filters;
}

//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================
<commit_msg>Fixed debug build crash on mac, reading from stringstream into emtpy string crashed when compiling with clang<commit_after>/*===========================================================================*\
 *                                                                           *
 *                               OpenMesh                                    *
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
 *                           www.openmesh.org                                *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenMesh.                                           *
 *                                                                           *
 *  OpenMesh 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 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  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 Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenMesh 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 LesserGeneral Public          *
 *  License along with OpenMesh.  If not,                                    *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/

/*===========================================================================*\
 *                                                                           *
 *   $Revision$                                                         *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/

//=============================================================================
//
//  Implements the OpenMesh IOManager singleton
//
//=============================================================================

//== INCLUDES =================================================================

#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/IO/IOManager.hh>

//== NAMESPACES ===============================================================

namespace OpenMesh {
namespace IO {

//=============================================================================

_IOManager_  *__IOManager_instance = 0;

_IOManager_& IOManager()
{

  if (!__IOManager_instance)
    __IOManager_instance = new _IOManager_();

  return *__IOManager_instance;
}

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

bool
_IOManager_::
read(const std::string& _filename, BaseImporter& _bi, Options& _opt)
{
  std::set<BaseReader*>::const_iterator it     =  reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end =  reader_modules_.end();

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_read(_filename))
    {
      _bi.prepare();
      bool ok = (*it)->read(_filename, _bi, _opt);
      _bi.finish();
      return ok;
    }

  // All modules failed to read
  return false;
}

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

bool
_IOManager_::
read(std::istream& _is, const std::string& _ext, BaseImporter& _bi, Options& _opt)
{
  std::set<BaseReader*>::const_iterator it     =  reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end =  reader_modules_.end();

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->BaseReader::can_u_read(_ext))  //Use the extension check only (no file existence)
    {
      _bi.prepare();
      bool ok = (*it)->read(_is, _bi, _opt);
      _bi.finish();
      return ok;
    }

  // All modules failed to read
  return false;
}

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

bool
_IOManager_::
write(const std::string& _filename, BaseExporter& _be, Options _opt)
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();

  if ( it == it_end )
  {
    omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n";
    return false;
  }

  // Try all registered modules
  for(; it != it_end; ++it)
  {
    if ((*it)->can_u_write(_filename))
    {
      return (*it)->write(_filename, _be, _opt);
    }
  }

  // All modules failed to save
  return false;
}

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

bool
_IOManager_::
write(std::ostream& _os,const std::string &_ext, BaseExporter& _be, Options _opt)
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();

  if ( it == it_end )
  {
    omerr() << "[OpenMesh::IO::_IOManager_] No writing modules available!\n";
    return false;
  }

  // Try all registered modules
  for(; it != it_end; ++it)
  {
    if ((*it)->BaseWriter::can_u_write(_ext)) //Restrict test to the extension check
    {
      return (*it)->write(_os, _be, _opt);
    }
  }

  // All modules failed to save
  return false;
}

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

bool
_IOManager_::
can_read( const std::string& _format ) const
{
  std::set<BaseReader*>::const_iterator it     = reader_modules_.begin();
  std::set<BaseReader*>::const_iterator it_end = reader_modules_.end();
  std::string filename = "dummy." + _format;

  for(; it != it_end; ++it)
    if ((*it)->can_u_read(filename))
      return true;

  return false;
}

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

bool
_IOManager_::
can_write( const std::string& _format ) const
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();
  std::string filename = "dummy." + _format;

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_write(filename))
      return true;

  return false;
}

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

const BaseWriter*
_IOManager_::
find_writer(const std::string& _format)
{
  using std::string;

  string::size_type dot = _format.rfind('.');

  string ext;
  if (dot == string::npos)
    ext = _format;
  else
    ext = _format.substr(dot+1,_format.length()-(dot+1));

  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin();
  std::set<BaseWriter*>::const_iterator it_end = writer_modules_.end();
  std::string filename = "dummy." + ext;

  // Try all registered modules
  for(; it != it_end; ++it)
    if ((*it)->can_u_write(filename))
      return *it;

  return NULL;
}

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

void
_IOManager_::
update_read_filters()
{
  std::set<BaseReader*>::const_iterator it     = reader_modules_.begin(),
                                        it_end = reader_modules_.end();
  std::string all = "";
  std::string filters = "";

  for(; it != it_end; ++it)
  {
    // Initialized with space, as a workaround for debug build with clang on mac
    // which crashes if tmp is initialized with an empty string ?!
    std::string tmp = " ";

    filters += (*it)->get_description() + " (";

    std::istringstream iss((*it)->get_extensions());

    while (iss && !iss.eof() && (iss >> tmp) )
    {
     tmp = " *." + tmp; filters += tmp; all += tmp;
    }

    filters += " );;";
  }

  all = "All files ( " + all + " );;";

  read_filters_ = all + filters;
}

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

void
_IOManager_::
update_write_filters()
{
  std::set<BaseWriter*>::const_iterator it     = writer_modules_.begin(),
                                        it_end = writer_modules_.end();
  std::string all;
  std::string filters;

  for(; it != it_end; ++it)
  {
    // Initialized with space, as a workaround for debug build with clang on mac
    // which crashes if tmp is initialized with an empty string ?!
    std::string s = " ";

    filters += (*it)->get_description() + " (";

    std::istringstream iss((*it)->get_extensions());
    while (iss && !iss.eof() && (iss >> s))
    { s = " *." + s; filters += s; all += s; }

    filters += " );;";
  }
  all = "All files ( " + all + " );;";

  write_filters_ = all + filters;
}

//=============================================================================
} // namespace IO
} // namespace OpenMesh
//=============================================================================
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "sink_rubber.hxx"
#include "istream/Sink.hxx"
#include "istream/UnusedPtr.hxx"
#include "rubber.hxx"
#include "pool/pool.hxx"
#include "util/Cancellable.hxx"

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>

class RubberSink final : IstreamSink, Cancellable {
    Rubber &rubber;
    unsigned rubber_id;

    const size_t max_size;
    size_t position = 0;

    RubberSinkHandler &handler;

public:
    template<typename I>
    RubberSink(Rubber &_rubber, unsigned _rubber_id, size_t _max_size,
               RubberSinkHandler &_handler,
               I &&_input,
               CancellablePointer &cancel_ptr)
        :IstreamSink(std::forward<I>(_input), FD_ANY),
         rubber(_rubber), rubber_id(_rubber_id), max_size(_max_size),
         handler(_handler) {
        cancel_ptr = *this;
    }

    void Read() noexcept {
        input.Read();
    }

private:
    void FailTooLarge();
    void InvokeEof();

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override;

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

static ssize_t
fd_read(FdType type, int fd, void *p, size_t size)
{
    return IsAnySocket(type)
        ? recv(fd, p, size, MSG_DONTWAIT)
        : read(fd, p, size);
}

void
RubberSink::FailTooLarge()
{
    rubber.Remove(rubber_id);

    if (input.IsDefined())
        input.ClearAndClose();

    handler.RubberTooLarge();
}

void
RubberSink::InvokeEof()
{
    if (input.IsDefined())
        input.ClearAndClose();

    if (position == 0) {
        /* the stream was empty; remove the object from the rubber
           allocator */
        rubber.Remove(rubber_id);
        rubber_id = 0;
    } else
        rubber.Shrink(rubber_id, position);

    handler.RubberDone(RubberAllocation(rubber, rubber_id), position);
}

/*
 * istream handler
 *
 */

inline size_t
RubberSink::OnData(const void *data, size_t length)
{
    assert(position <= max_size);

    if (position + length > max_size) {
        /* too large, abort and invoke handler */

        FailTooLarge();
        return 0;
    }

    uint8_t *p = (uint8_t *)rubber.Write(rubber_id);
    memcpy(p + position, data, length);
    position += length;

    return length;
}

inline ssize_t
RubberSink::OnDirect(FdType type, int fd, size_t max_length)
{
    assert(position <= max_size);

    size_t length = max_size - position;
    if (length == 0) {
        /* already full, see what the file descriptor says */

        uint8_t dummy;
        ssize_t nbytes = fd_read(type, fd, &dummy, sizeof(dummy));
        if (nbytes > 0) {
            FailTooLarge();
            return ISTREAM_RESULT_CLOSED;
        }

        if (nbytes == 0) {
            InvokeEof();
            return ISTREAM_RESULT_CLOSED;
        }

        return ISTREAM_RESULT_ERRNO;
    }

    if (length > max_length)
        length = max_length;

    uint8_t *p = (uint8_t *)rubber.Write(rubber_id);
    p += position;

    ssize_t nbytes = fd_read(type, fd, p, length);
    if (nbytes > 0)
        position += (size_t)nbytes;

    return nbytes;
}

void
RubberSink::OnEof() noexcept
{
    assert(input.IsDefined());
    input.Clear();

    InvokeEof();
}

void
RubberSink::OnError(std::exception_ptr ep) noexcept
{
    assert(input.IsDefined());
    input.Clear();

    rubber.Remove(rubber_id);
    handler.RubberError(ep);
}

/*
 * async operation
 *
 */

void
RubberSink::Cancel() noexcept
{
    rubber.Remove(rubber_id);

    if (input.IsDefined())
        input.ClearAndClose();
}

/*
 * constructor
 *
 */

RubberSink *
sink_rubber_new(struct pool &pool, UnusedIstreamPtr input,
                Rubber &rubber, size_t max_size,
                RubberSinkHandler &handler,
                CancellablePointer &cancel_ptr)
{
    const off_t available = input.GetAvailable(true);
    if (available > (off_t)max_size) {
        input.Clear();
        handler.RubberTooLarge();
        return nullptr;
    }

    const off_t size = input.GetAvailable(false);
    assert(size == -1 || size >= available);
    assert(size <= (off_t)max_size);
    if (size == 0) {
        input.Clear();
        handler.RubberDone({}, 0);
        return nullptr;
    }

    const size_t allocate = size == -1
        ? max_size
        : (size_t)size;

    unsigned rubber_id = rubber.Add(allocate);
    if (rubber_id == 0) {
        input.Clear();
        handler.RubberOutOfMemory();
        return nullptr;
    }

    return NewFromPool<RubberSink>(pool, rubber, rubber_id, allocate,
                                   handler,
                                   std::move(input), cancel_ptr);
}

void
sink_rubber_read(RubberSink &sink) noexcept
{
    sink.Read();
}
<commit_msg>sink_rubber: call destructor<commit_after>/*
 * Copyright 2007-2017 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION 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 "sink_rubber.hxx"
#include "istream/Sink.hxx"
#include "istream/UnusedPtr.hxx"
#include "rubber.hxx"
#include "pool/pool.hxx"
#include "util/Cancellable.hxx"
#include "util/LeakDetector.hxx"

#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>

class RubberSink final : IstreamSink, Cancellable, LeakDetector {
    Rubber &rubber;
    unsigned rubber_id;

    const size_t max_size;
    size_t position = 0;

    RubberSinkHandler &handler;

public:
    template<typename I>
    RubberSink(Rubber &_rubber, unsigned _rubber_id, size_t _max_size,
               RubberSinkHandler &_handler,
               I &&_input,
               CancellablePointer &cancel_ptr)
        :IstreamSink(std::forward<I>(_input), FD_ANY),
         rubber(_rubber), rubber_id(_rubber_id), max_size(_max_size),
         handler(_handler) {
        cancel_ptr = *this;
    }

    void Read() noexcept {
        input.Read();
    }

private:
    void Destroy() {
        this->~RubberSink();
    }

    void FailTooLarge();
    void InvokeEof();

    /* virtual methods from class Cancellable */
    void Cancel() noexcept override;

    /* virtual methods from class IstreamHandler */
    size_t OnData(const void *data, size_t length) override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

static ssize_t
fd_read(FdType type, int fd, void *p, size_t size)
{
    return IsAnySocket(type)
        ? recv(fd, p, size, MSG_DONTWAIT)
        : read(fd, p, size);
}

void
RubberSink::FailTooLarge()
{
    rubber.Remove(rubber_id);

    if (input.IsDefined())
        input.ClearAndClose();

    handler.RubberTooLarge();
}

void
RubberSink::InvokeEof()
{
    if (input.IsDefined())
        input.ClearAndClose();

    if (position == 0) {
        /* the stream was empty; remove the object from the rubber
           allocator */
        rubber.Remove(rubber_id);
        rubber_id = 0;
    } else
        rubber.Shrink(rubber_id, position);

    handler.RubberDone(RubberAllocation(rubber, rubber_id), position);
}

/*
 * istream handler
 *
 */

inline size_t
RubberSink::OnData(const void *data, size_t length)
{
    assert(position <= max_size);

    if (position + length > max_size) {
        /* too large, abort and invoke handler */

        FailTooLarge();
        Destroy();
        return 0;
    }

    uint8_t *p = (uint8_t *)rubber.Write(rubber_id);
    memcpy(p + position, data, length);
    position += length;

    return length;
}

inline ssize_t
RubberSink::OnDirect(FdType type, int fd, size_t max_length)
{
    assert(position <= max_size);

    size_t length = max_size - position;
    if (length == 0) {
        /* already full, see what the file descriptor says */

        uint8_t dummy;
        ssize_t nbytes = fd_read(type, fd, &dummy, sizeof(dummy));
        if (nbytes > 0) {
            FailTooLarge();
            Destroy();
            return ISTREAM_RESULT_CLOSED;
        }

        if (nbytes == 0) {
            InvokeEof();
            Destroy();
            return ISTREAM_RESULT_CLOSED;
        }

        return ISTREAM_RESULT_ERRNO;
    }

    if (length > max_length)
        length = max_length;

    uint8_t *p = (uint8_t *)rubber.Write(rubber_id);
    p += position;

    ssize_t nbytes = fd_read(type, fd, p, length);
    if (nbytes > 0)
        position += (size_t)nbytes;

    return nbytes;
}

void
RubberSink::OnEof() noexcept
{
    assert(input.IsDefined());
    input.Clear();

    InvokeEof();
    Destroy();
}

void
RubberSink::OnError(std::exception_ptr ep) noexcept
{
    assert(input.IsDefined());
    input.Clear();

    rubber.Remove(rubber_id);
    handler.RubberError(ep);
    Destroy();
}

/*
 * async operation
 *
 */

void
RubberSink::Cancel() noexcept
{
    rubber.Remove(rubber_id);

    if (input.IsDefined())
        input.ClearAndClose();

    Destroy();
}

/*
 * constructor
 *
 */

RubberSink *
sink_rubber_new(struct pool &pool, UnusedIstreamPtr input,
                Rubber &rubber, size_t max_size,
                RubberSinkHandler &handler,
                CancellablePointer &cancel_ptr)
{
    const off_t available = input.GetAvailable(true);
    if (available > (off_t)max_size) {
        input.Clear();
        handler.RubberTooLarge();
        return nullptr;
    }

    const off_t size = input.GetAvailable(false);
    assert(size == -1 || size >= available);
    assert(size <= (off_t)max_size);
    if (size == 0) {
        input.Clear();
        handler.RubberDone({}, 0);
        return nullptr;
    }

    const size_t allocate = size == -1
        ? max_size
        : (size_t)size;

    unsigned rubber_id = rubber.Add(allocate);
    if (rubber_id == 0) {
        input.Clear();
        handler.RubberOutOfMemory();
        return nullptr;
    }

    return NewFromPool<RubberSink>(pool, rubber, rubber_id, allocate,
                                   handler,
                                   std::move(input), cancel_ptr);
}

void
sink_rubber_read(RubberSink &sink) noexcept
{
    sink.Read();
}
<|endoftext|>


<commit_before>/* http_header.cc
   Mathieu Stefani, 19 August 2015

   Implementation of common HTTP headers described by the RFC
*/

#include "http_header.h"
#include "common.h"
#include "http.h"
#include <stdexcept>
#include <iterator>
#include <cstring>
#include <iostream>

using namespace std;

namespace Net {

namespace Http {

namespace Mime {

std::string
Q::toString() const {
    if (val_ == 0)
        return "q=0";
    else if (val_ == 100)
        return "q=1";

    char buff[sizeof("q=0.99")];
    memset(buff, sizeof buff, 0);
    if (val_ % 10 == 0)
        snprintf(buff, sizeof buff, "q=%.1f", val_ / 100.0);
    else
        snprintf(buff, sizeof buff, "q=%.2f", val_ / 100.0);

    return std::string(buff);
}

MediaType
MediaType::fromString(const std::string& str) {
    return fromRaw(str.c_str(), str.size());
}

MediaType
MediaType::fromString(std::string&& str) {
    return fromRaw(str.c_str(), str.size());
}

MediaType
MediaType::fromRaw(const char* str, size_t len) {
    MediaType res;

    res.parseRaw(str, len);
    return res;
}

void
MediaType::parseRaw(const char* str, size_t len) {
    auto eof = [&](const char *p) {
        return p - str == len;
    };

    auto offset = [&](const char* ptr) {
        return static_cast<size_t>(ptr - str);
    };

    auto raise = [&](const char* str) {
        throw HttpError(Http::Code::Unsupported_Media_Type, str);
    };

    #define MAX_SIZE(s) std::min(sizeof(s) - 1, offset(p))

    // Parse type
    const char *p = strchr(str, '/');
    if (p == NULL) {
        raise("Malformated Media Type");
    }

    raw_ = string(str, len);

    Mime::Type top;

    // The reason we are using a do { } while (0); syntax construct here is to emulate
    // if / else-if. Since we are using items-list macros to compare the strings,
    // we want to avoid evaluating all the branches when one of them evaluates to true.
    //
    // Instead, we break the loop when a branch evaluates to true so that we do
    // not evaluate all the subsequent ones.
    //
    // Watch out, this pattern is repeated throughout the function
    do {
#define TYPE(val, s)                            \
        if (memcmp(str, s, MAX_SIZE(s)) == 0) { \
            top = Type::val;                    \
            break;                              \
        }
        MIME_TYPES
#undef TYPE
        throw HttpError(Http::Code::Unsupported_Media_Type, "Unknown Media Type");
    } while (0);

    top_ = top;

    // Parse subtype
    Mime::Subtype sub;
    ++p;

    if (eof(p)) raise("Malformed Media Type");

    if (memcmp(p, "vnd.", 4) == 0) {
        sub = Subtype::Vendor;
    } else {
        do {
#define SUB_TYPE(val, s) \
            if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
                sub = Subtype::val; \
                p += sizeof(s) - 1; \
                break; \
            }
            MIME_SUBTYPES
#undef SUB_TYPE
            sub = Subtype::Ext;
        } while (0);
    }

    if (sub == Subtype::Ext || sub == Subtype::Vendor) {
        rawSubIndex.beg = offset(p);
        while (!eof(p) && (*p != ';' && *p != '+')) ++p;
        rawSubIndex.end = offset(p) - 1;
    }

    sub_ = sub;

    if (eof(p)) return;

    // Parse suffix
    Mime::Suffix suffix = Suffix::None;
    if (*p == '+') {

        ++p;

        if (eof(p)) raise("Malformed Media Type");

        do {
#define SUFFIX(val, s, _) \
            if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
                suffix = Suffix::val; \
                p += sizeof(s) - 1; \
                break; \
            }
            MIME_SUFFIXES
#undef SUFFIX
            suffix = Suffix::Ext;
        } while (0);

        if (suffix == Suffix::Ext) {
            rawSuffixIndex.beg = offset(p);
            while (!eof(p) && (*p != ';' && *p != '+')) ++p;
            rawSuffixIndex.end = offset(p) - 1;
        }

        suffix_ = suffix;
    }

    if (eof(p)) return;

    if (*p == ';') ++p;

    if (eof(p)) {
        raise("Malformed Media Type");
    }

    while (*p == ' ') ++p;

    if (eof(p)) {
        raise("Malformed Media Type");
    };

    Optional<Q> q = None();

    if (*p == 'q') {
        ++p;

        if (eof(p)) {
            raise("Invalid quality factor");
        }

        if (*p == '=') {
            char *end;
            double val = strtod(p + 1, &end);
            if (!eof(end) && *end != ';' && *end != ' ') {
                raise("Invalid quality factor");
            }
            q = Some(Q::fromFloat(val));
        }
        else {
            raise("Invalid quality factor");
        }
    }

    q_ = std::move(q);

    #undef MAX_SIZE

}

void
MediaType::setQuality(Q quality) {
    q_ = Some(quality);
}

std::string
MediaType::toString() const {

    if (!raw_.empty()) return raw_;

    auto topString = [](Mime::Type top) -> const char * {
        switch (top) {
#define TYPE(val, str) \
        case Mime::Type::val: \
            return str;
        MIME_TYPES
#undef TYPE
        }
    };

    auto subString = [](Mime::Subtype sub) -> const char * {
        switch (sub) {
#define SUB_TYPE(val, str) \
        case Mime::Subtype::val: \
            return str;
        MIME_SUBTYPES
#undef TYPE
        }
    };

    auto suffixString = [](Mime::Suffix suffix) -> const char * {
        switch (suffix) {
#define SUFFIX(val, str, _) \
        case Mime::Suffix::val: \
            return "+" str;
        MIME_SUFFIXES
#undef SUFFIX
        }
    };

    std::string res;
    res += topString(top_);
    res += "/";
    res += subString(sub_);
    if (suffix_ != Suffix::None) {
        res += suffixString(suffix_);
    }

    optionally_do(q_, [&res](Q quality) {
        res += "; ";
        res += quality.toString();
    });

    return res;
}

} // namespace Mime

const char* encodingString(Encoding encoding) {
    switch (encoding) {
    case Encoding::Gzip:
        return "gzip";
    case Encoding::Compress:
        return "compress";
    case Encoding::Deflate:
        return "deflate";
    case Encoding::Identity:
        return "identity";
    case Encoding::Unknown:
        return "unknown";
    }

    unreachable();
}

void
Header::parse(const std::string& data) {
    parseRaw(data.c_str(), data.size());
}

void
Header::parseRaw(const char *str, size_t len) {
    parse(std::string(str, len));
}

void
ContentLength::parse(const std::string& data) {
    try {
        size_t pos;
        uint64_t val = std::stoi(data, &pos);
        if (pos != 0) {
        }

        value_ = val;
    } catch (const std::invalid_argument& e) {
    }
}

void
ContentLength::write(std::ostream& os) const {
    os << "Content-Length: " << value_;
}

void
Host::parse(const std::string& data) {
    auto pos = data.find(':');
    if (pos != std::string::npos) {
        std::string h = data.substr(0, pos);
        int16_t p = std::stoi(data.substr(pos + 1));

        host_ = h;
        port_ = p;
    } else {
        host_ = data;
        port_ = -1;
    }
}

void
Host::write(std::ostream& os) const {
    os << host_;
    if (port_ != -1) {
        os << ":" << port_;
    }
}

void
UserAgent::parse(const std::string& data) {
    ua_ = data;
}

void
UserAgent::write(std::ostream& os) const {
    os << "User-Agent: " << ua_;
}

void
Accept::parseRaw(const char *str, size_t len) {
}

void
Accept::write(std::ostream& os) const {
}

void
ContentEncoding::parseRaw(const char* str, size_t len) {
    // TODO: case-insensitive
    //
    if (!strncmp(str, "gzip", len)) {
        encoding_ = Encoding::Gzip;
    }
    else if (!strncmp(str, "deflate", len)) {
        encoding_ = Encoding::Deflate;
    }
    else if (!strncmp(str, "compress", len)) {
        encoding_ = Encoding::Compress;
    }
    else if (!strncmp(str, "identity", len)) {
        encoding_ = Encoding::Identity;
    }
    else {
        encoding_ = Encoding::Unknown;
    }
}

void
ContentEncoding::write(std::ostream& os) const {
    os << "Content-Encoding: " << encodingString(encoding_);
}

Server::Server(const std::vector<std::string>& tokens)
    : tokens_(tokens)
{ }

Server::Server(const std::string& token)
{
    tokens_.push_back(token);
}

Server::Server(const char* token)
{
    tokens_.emplace_back(token);
}

void
Server::parse(const std::string& data)
{
}

void
Server::write(std::ostream& os) const
{
    os << "Server: ";
    std::copy(std::begin(tokens_), std::end(tokens_),
                 std::ostream_iterator<std::string>(os, " "));
}

void
ContentType::parseRaw(const char* str, size_t len)
{
}

void
ContentType::write(std::ostream& os) const {
    os << "Content-Type: ";
    os << mime_.toString();
}

} // namespace Http

} // namespace Net
<commit_msg>Fixed the MAX_SIZE macro that was incorrectly calculating the maximum remaining size<commit_after>/* http_header.cc
   Mathieu Stefani, 19 August 2015

   Implementation of common HTTP headers described by the RFC
*/

#include "http_header.h"
#include "common.h"
#include "http.h"
#include <stdexcept>
#include <iterator>
#include <cstring>
#include <iostream>

using namespace std;

namespace Net {

namespace Http {

namespace Mime {

std::string
Q::toString() const {
    if (val_ == 0)
        return "q=0";
    else if (val_ == 100)
        return "q=1";

    char buff[sizeof("q=0.99")];
    memset(buff, sizeof buff, 0);
    if (val_ % 10 == 0)
        snprintf(buff, sizeof buff, "q=%.1f", val_ / 100.0);
    else
        snprintf(buff, sizeof buff, "q=%.2f", val_ / 100.0);

    return std::string(buff);
}

MediaType
MediaType::fromString(const std::string& str) {
    return fromRaw(str.c_str(), str.size());
}

MediaType
MediaType::fromString(std::string&& str) {
    return fromRaw(str.c_str(), str.size());
}

MediaType
MediaType::fromRaw(const char* str, size_t len) {
    MediaType res;

    res.parseRaw(str, len);
    return res;
}

void
MediaType::parseRaw(const char* str, size_t len) {
    auto eof = [&](const char *p) {
        return p - str == len;
    };

    auto offset = [&](const char* ptr) {
        return static_cast<size_t>(ptr - str);
    };

    auto raise = [&](const char* str) {
        // TODO: eventually, we should throw a more generic exception
        // that could then be catched in lower stack frames to rethrow
        // an HttpError
        throw HttpError(Http::Code::Unsupported_Media_Type, str);
    };

    // Macro to ensure that we do not overflow when comparing strings
    // The trick here is to use sizeof on a raw string literal of type
    // const char[N] instead of strlen to avoid additional
    // runtime computation
    #define MAX_SIZE(s) std::min(sizeof(s) - 1, len - offset(p))

    // Parse type
    const char *p = strchr(str, '/');
    if (p == NULL) {
        raise("Malformated Media Type");
    }

    raw_ = string(str, len);

    Mime::Type top;

    // The reason we are using a do { } while (0); syntax construct here is to emulate
    // if / else-if. Since we are using items-list macros to compare the strings,
    // we want to avoid evaluating all the branches when one of them evaluates to true.
    //
    // Instead, we break the loop when a branch evaluates to true so that we do
    // not evaluate all the subsequent ones.
    //
    // Watch out, this pattern is repeated throughout the function
    do {
#define TYPE(val, s)                            \
        if (memcmp(str, s, MAX_SIZE(s)) == 0) { \
            top = Type::val;                    \
            break;                              \
        }
        MIME_TYPES
#undef TYPE
        raise("Unknown Media Type");
    } while (0);

    top_ = top;

    // Parse subtype
    Mime::Subtype sub;
    ++p;

    if (eof(p)) raise("Malformed Media Type");

    if (memcmp(p, "vnd.", MAX_SIZE("vnd.")) == 0) {
        sub = Subtype::Vendor;
    } else {
        do {
#define SUB_TYPE(val, s)                          \
            if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
                sub = Subtype::val;               \
                p += sizeof(s) - 1;               \
                break;                            \
            }
            MIME_SUBTYPES
#undef SUB_TYPE
            sub = Subtype::Ext;
        } while (0);
    }

    if (sub == Subtype::Ext || sub == Subtype::Vendor) {
        rawSubIndex.beg = offset(p);
        while (!eof(p) && (*p != ';' && *p != '+')) ++p;
        rawSubIndex.end = offset(p) - 1;
    }

    sub_ = sub;

    if (eof(p)) return;

    // Parse suffix
    Mime::Suffix suffix = Suffix::None;
    if (*p == '+') {

        ++p;

        if (eof(p)) raise("Malformed Media Type");

        do {
#define SUFFIX(val, s, _)                         \
            if (memcmp(p, s, MAX_SIZE(s)) == 0) { \
                suffix = Suffix::val;             \
                p += sizeof(s) - 1;               \
                break;                            \
            }
            MIME_SUFFIXES
#undef SUFFIX
            suffix = Suffix::Ext;
        } while (0);

        if (suffix == Suffix::Ext) {
            rawSuffixIndex.beg = offset(p);
            while (!eof(p) && (*p != ';' && *p != '+')) ++p;
            rawSuffixIndex.end = offset(p) - 1;
        }

        suffix_ = suffix;
    }

    if (eof(p)) return;

    if (*p == ';') ++p;

    if (eof(p)) {
        raise("Malformed Media Type");
    }

    while (*p == ' ') ++p;

    if (eof(p)) {
        raise("Malformed Media Type");
    };

    Optional<Q> q = None();

    if (*p == 'q') {
        ++p;

        if (eof(p)) {
            raise("Invalid quality factor");
        }

        if (*p == '=') {
            char *end;
            double val = strtod(p + 1, &end);
            if (!eof(end) && *end != ';' && *end != ' ') {
                raise("Invalid quality factor");
            }
            q = Some(Q::fromFloat(val));
        }
        else {
            raise("Invalid quality factor");
        }
    }

    q_ = std::move(q);

    #undef MAX_SIZE

}

void
MediaType::setQuality(Q quality) {
    q_ = Some(quality);
}

std::string
MediaType::toString() const {

    if (!raw_.empty()) return raw_;

    auto topString = [](Mime::Type top) -> const char * {
        switch (top) {
#define TYPE(val, str)        \
        case Mime::Type::val: \
            return str;
        MIME_TYPES
#undef TYPE
        }
    };

    auto subString = [](Mime::Subtype sub) -> const char * {
        switch (sub) {
#define SUB_TYPE(val, str)       \
        case Mime::Subtype::val: \
            return str;
        MIME_SUBTYPES
#undef TYPE
        }
    };

    auto suffixString = [](Mime::Suffix suffix) -> const char * {
        switch (suffix) {
#define SUFFIX(val, str, _)     \
        case Mime::Suffix::val: \
            return "+" str;
        MIME_SUFFIXES
#undef SUFFIX
        }
    };

    std::string res;
    res += topString(top_);
    res += "/";
    res += subString(sub_);
    if (suffix_ != Suffix::None) {
        res += suffixString(suffix_);
    }

    optionally_do(q_, [&res](Q quality) {
        res += "; ";
        res += quality.toString();
    });

    return res;
}

} // namespace Mime

const char* encodingString(Encoding encoding) {
    switch (encoding) {
    case Encoding::Gzip:
        return "gzip";
    case Encoding::Compress:
        return "compress";
    case Encoding::Deflate:
        return "deflate";
    case Encoding::Identity:
        return "identity";
    case Encoding::Unknown:
        return "unknown";
    }

    unreachable();
}

void
Header::parse(const std::string& data) {
    parseRaw(data.c_str(), data.size());
}

void
Header::parseRaw(const char *str, size_t len) {
    parse(std::string(str, len));
}

void
ContentLength::parse(const std::string& data) {
    try {
        size_t pos;
        uint64_t val = std::stoi(data, &pos);
        if (pos != 0) {
        }

        value_ = val;
    } catch (const std::invalid_argument& e) {
    }
}

void
ContentLength::write(std::ostream& os) const {
    os << "Content-Length: " << value_;
}

void
Host::parse(const std::string& data) {
    auto pos = data.find(':');
    if (pos != std::string::npos) {
        std::string h = data.substr(0, pos);
        int16_t p = std::stoi(data.substr(pos + 1));

        host_ = h;
        port_ = p;
    } else {
        host_ = data;
        port_ = -1;
    }
}

void
Host::write(std::ostream& os) const {
    os << host_;
    if (port_ != -1) {
        os << ":" << port_;
    }
}

void
UserAgent::parse(const std::string& data) {
    ua_ = data;
}

void
UserAgent::write(std::ostream& os) const {
    os << "User-Agent: " << ua_;
}

void
Accept::parseRaw(const char *str, size_t len) {
}

void
Accept::write(std::ostream& os) const {
}

void
ContentEncoding::parseRaw(const char* str, size_t len) {
    // TODO: case-insensitive
    //
    if (!strncmp(str, "gzip", len)) {
        encoding_ = Encoding::Gzip;
    }
    else if (!strncmp(str, "deflate", len)) {
        encoding_ = Encoding::Deflate;
    }
    else if (!strncmp(str, "compress", len)) {
        encoding_ = Encoding::Compress;
    }
    else if (!strncmp(str, "identity", len)) {
        encoding_ = Encoding::Identity;
    }
    else {
        encoding_ = Encoding::Unknown;
    }
}

void
ContentEncoding::write(std::ostream& os) const {
    os << "Content-Encoding: " << encodingString(encoding_);
}

Server::Server(const std::vector<std::string>& tokens)
    : tokens_(tokens)
{ }

Server::Server(const std::string& token)
{
    tokens_.push_back(token);
}

Server::Server(const char* token)
{
    tokens_.emplace_back(token);
}

void
Server::parse(const std::string& data)
{
}

void
Server::write(std::ostream& os) const
{
    os << "Server: ";
    std::copy(std::begin(tokens_), std::end(tokens_),
                 std::ostream_iterator<std::string>(os, " "));
}

void
ContentType::parseRaw(const char* str, size_t len)
{
}

void
ContentType::write(std::ostream& os) const {
    os << "Content-Type: ";
    os << mime_.toString();
}

} // namespace Http

} // namespace Net
<|endoftext|>


<commit_before>// TODO(ralntdir):
// Think how to clean SDL if the programs ends with some crash
// Finished the program if there is a problem at SDL/IMG init or
// when creating the window or the renderer
//
// Features to add:
// ray->sphere intersection (check if it's completed)
// shadows
// reflection
// read llc, hoffset and voffset from file

// Files manipulation
#include <iostream>
#include <fstream>
#include <string>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

// NOTE(ralntdir): For number types
#include <stdint.h>

// NOTE(ralntdir): For rand
#include <random>

// NOTE(ralntdir): For FLT_MAX
#include <float.h>

typedef int32_t int32;

typedef float real32;
typedef double real64;

// TODO(ralntdir): read this from a scene file?
#define WIDTH 500
#define HEIGHT 500
#define MAX_COLOR 255
#define MAX_SAMPLES 100
#define MAX_DEPTH 5

#include <math.h>
#include "myMath.h"

struct ray
{
  vec3 origin;
  vec3 direction;
};

struct sphere
{
  vec3 center;
  real32 radius;

  vec3 ka;
  vec3 kd;
  vec3 ks;

  vec3 kr;

  real32 alpha;
};

enum light_type
{
  point,
  directional,
};

struct light
{
  vec3 position;
  vec3 intensity;
  light_type type;
};

struct scene
{
  vec3 camera;
  vec3 ul;
  vec3 ur;
  vec3 lr;
  vec3 ll;

  int32 maxSpheres = 8;
  int32 maxLights = 2;

  int32 numSpheres;
  int32 numLights;
  light lights[2];
  sphere spheres[8];
};

bool hitSphere(sphere mySphere, ray myRay, real32 *t)
{
  bool result = false;

  vec3 originCenter = myRay.origin - mySphere.center;

  real32 a = dotProduct(myRay.direction, myRay.direction);
  real32 b = 2 * dotProduct(originCenter, myRay.direction);
  real32 c = dotProduct(originCenter, originCenter) - mySphere.radius*mySphere.radius;

  real32 discriminant = b*b - 4*a*c;

  if (discriminant < 0)
  {
    return(result);
  }
  else
  {
    result = true;

    real32 root1 = (-b + sqrt(discriminant))/(2*a);
    real32 root2 = (-b - sqrt(discriminant))/(2*a);

    if ((root1 < root2) && (root1 > 0.0))
    {
      *t = root1;
    }
    else if ((root2 < root1) && (root2 > 0.0))
    {
      *t = root2;
    }
    else if ((root1 < 0) && (root2 < 0))
    {
      result = false;
    }
  }

  return(result);
}

// TODO(ralntdir): add attenuation for point lights
// TODO(ralntdir): technically this is not Phong Shading
vec3 phongShading(light myLight, sphere mySphere, vec3 camera, vec3 hitPoint, real32 visible, int32 depth)
{
  vec3 result;

  // *N vector (normal at hit point)
  // *L vector (lightPosition - hitPoint)
  vec3 N = normalize(hitPoint - mySphere.center);
  vec3 L = {};
  if (myLight.type == point)
  {
    L = normalize(myLight.position - hitPoint);
  }
  else if (myLight.type == directional)
  {
    L = normalize(-myLight.position);
  }
  real32 dotProductLN = max(dotProduct(L, N), 0.0);
  real32 filterSpecular = dotProductLN > 0.0 ? 1.0 : 0.0;

  // *R vector (reflection of L -> 2(L·N)N - L)
  // *V vector (camera - hitPoint)
  vec3 R = normalize(2*dotProduct(L, N)*N - L);
  vec3 V = normalize(camera - hitPoint);

  // Only add specular component if you have diffuse,
  // if dotProductLN > 0.0
  if (depth == 1)
  {
    result = mySphere.ka*myLight.intensity +
             visible*mySphere.kd*myLight.intensity*dotProductLN +
             visible*filterSpecular*mySphere.ks*myLight.intensity*pow(max(dotProduct(R, V), 0.0), mySphere.alpha);
  }
  else if (depth > 1)
  {
    result = visible*mySphere.kd*myLight.intensity*dotProductLN +
             visible*filterSpecular*mySphere.ks*myLight.intensity*pow(max(dotProduct(R, V), 0.0), mySphere.alpha);
  }

  return(result);
}

ray getShadowRay(light myLight, vec3 hitPoint, vec3 normalAtHitPoint)
{
  ray result = {};

  // NOTE(ralntdir): delta to avoid shadow acne.
  real32 bias = 0.01;

  result.origin = hitPoint + normalAtHitPoint*bias;

  if (myLight.type == directional)
  {
    result.direction = normalize(-myLight.position);
  }
  else if (myLight.type == point)
  {
    result.direction = normalize(myLight.position - hitPoint);
  }

  return(result);
}

vec3 color(ray myRay, scene *myScene, vec3 backgroundColor, int32 depth)
{
  // vec3 result = backgroundColor;
  vec3 result = { 0.0, 0.0, 0.0 };

  if (depth <= MAX_DEPTH)
  {
    real32 maxt = FLT_MAX;
    real32 t = -1.0;

    for (int i = 0; i < myScene->numSpheres; i++)
    {
      sphere mySphere = myScene->spheres[i];
      if (hitSphere(mySphere, myRay, &t))
      {
        if ((t >= 0.0) && (t < maxt))
        {
          result = {};
          maxt = t;
          vec3 hitPoint = myRay.origin + t*myRay.direction;

          vec3 N = normalize(hitPoint - mySphere.center);

          for (int j = 0; j < myScene->numLights; j++)
          {
            light myLight = myScene->lights[j];

            ray shadowRay = getShadowRay(myLight, hitPoint, N);

            real32 visible = 1.0;

            for (int k = 0; k < myScene->numSpheres; k++)
            {
              if (i != k)
              {
                sphere mySphere1 = myScene->spheres[k];
                real32 t1 = -1.0;
                if (hitSphere(mySphere1, shadowRay, &t1))
                {
                  visible = 0.0;
                  break;
                }
              }
            }
            result += phongShading(myLight, mySphere, myScene->camera, hitPoint, visible, depth);
          }

          // Add reflection
          ray reflectedRay = {};
          reflectedRay.origin = hitPoint + N*0.01;
          reflectedRay.direction = 2*dotProduct(-myRay.direction, N)*N + myRay.direction;

          result += mySphere.kr*color(reflectedRay, myScene, backgroundColor, depth+1);
        }
      }
    }
  }
  return(result);
}

void readSceneFile(scene *myScene, char *filename)
{
  std::string line;
  std::ifstream scene(filename);

  if (scene.is_open())
  {
    while (!scene.eof())
    {
      scene >> line;

      // If line is not a comment
      if (line[0] == '#')
      {
        std::getline(scene, line);
        std::cout << line << "\n";
      }
      else
      {
        std::cout << line << "\n";

        if (line == "camera")
        {
          scene >> myScene->camera.x;
          scene >> myScene->camera.y;
          scene >> myScene->camera.z;
        }
        else if (line == "sphere")
        {
          sphere mySphere = {};

          scene >> line; // center
          scene >> mySphere.center.x;
          scene >> mySphere.center.y;
          scene >> mySphere.center.z;
          scene >> line; // radius
          scene >> mySphere.radius;
          scene >> line; // ka
          scene >> mySphere.ka.x;
          scene >> mySphere.ka.y;
          scene >> mySphere.ka.z;
          scene >> line; // kd
          scene >> mySphere.kd.x;
          scene >> mySphere.kd.y;
          scene >> mySphere.kd.z;
          scene >> line; // ks
          scene >> mySphere.ks.x;
          scene >> mySphere.ks.y;
          scene >> mySphere.ks.z;
          scene >> line; // kr || alpha
          if (line == "kr")
          {
            scene >> mySphere.kr.x;
            scene >> mySphere.kr.y;
            scene >> mySphere.kr.z;
            scene >> line; // alpha
            scene >> mySphere.alpha;
          }
          else if (line == "alpha")
          {
            scene >> mySphere.alpha;
          }

          myScene->numSpheres++;
          if (myScene->numSpheres <= myScene->maxSpheres)
          {
            myScene->spheres[myScene->numSpheres-1] = mySphere;
          }
        }
        else if (line == "light")
        {
          light myLight = {};

          scene >> line; // position
          scene >> myLight.position.x;
          scene >> myLight.position.y;
          scene >> myLight.position.z;
          scene >> line; // intensity
          scene >> myLight.intensity.x;
          scene >> myLight.intensity.y;
          scene >> myLight.intensity.z;
          scene >> line; // type
          scene >> line;

          if (line.compare("point") == 0)
          {
            myLight.type = point;
          }
          else if (line.compare("directional") == 0)
          {
            myLight.type = directional;
          }

          myScene->numLights++;
          if (myScene->numLights <= myScene->maxLights)
          {
            myScene->lights[myScene->numLights-1] = myLight;
          }
        }
        else if (line == "ul")
        {
          vec3 ul = {};
          scene >> ul.x;
          scene >> ul.y;
          scene >> ul.z;

          myScene->ul = ul;
        }
        else if (line == "ur")
        {
          vec3 ur = {};
          scene >> ur.x;
          scene >> ur.y;
          scene >> ur.z;

          myScene->ur = ur;
        }
        else if (line == "lr")
        {
          vec3 lr = {};
          scene >> lr.x;
          scene >> lr.y;
          scene >> lr.z;

          myScene->lr = lr;
        }
        else if (line == "ll")
        {
          vec3 ll = {};
          scene >> ll.x;
          scene >> ll.y;
          scene >> ll.z;

          myScene->ll = ll;
        }
      }
    }
    scene.close();
  }
  else
  {
    std::cout << "There was a problem opening the scene file\n";
  }
}

int main(int argc, char* argv[])
{
  SDL_Window *window;
  SDL_Renderer *renderer;
  SDL_Surface *surface;
  SDL_Texture *texture;

  if (argc < 2)
  {
    std::cout << "Missing scene file. Usage: ./program sceneFile\n";
    return(1);
  }
  char *sceneFileName = argv[1];

  // Init SDL
  if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  {
    std::cout << "Error in SDL_Init(): " << SDL_GetError() << "\n";
  }

  // Init SDL_Image
  if (IMG_Init(0) < 0)
  {
    std::cout << "Error in IMG_Init(): " << IMG_GetError() << "\n";
  }

  // Create a Window
  // NOTE(ralntdir): SDL_WINDOW_SHOWN is ignored by SDL_CreateWindow().
  // The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set.
  window = SDL_CreateWindow("Devember RT", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                            WIDTH, HEIGHT, SDL_WINDOW_SHOWN);

  if (window == 0)
  {
    std::cout << "Error in SDL_CreateWindow(): " << SDL_GetError() << "\n";
  }

  // Create a Renderer
  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  if (renderer == 0)
  {
    std::cout << "Error in SDL_CreateRenderer(): " << SDL_GetError() << "\n";
  }

  scene myScene = {};
  // Read scene file
  readSceneFile(&myScene, sceneFileName);

  // Create a .ppm file
  std::ofstream ofs("image.ppm", std::ofstream::out | std::ofstream::binary);

  ofs << "P3\n";
  ofs << "# image.ppm\n";
  ofs << WIDTH << " " << HEIGHT << "\n";
  ofs << MAX_COLOR << "\n";

  vec3 horizontalOffset = myScene.ur - myScene.ul;
  vec3 verticalOffset = myScene.ul - myScene.ll;
  vec3 lowerLeftCorner = myScene.ll;

  // NOTE(ralntdir): generates random unsigned integers
  std::default_random_engine engine;
  // NOTE(ralntdir): generates random floats between [0, 1)
  std::uniform_real_distribution<real32> distribution(0, 1);

  int32 depth = 1;

  // NOTE(ralntdir): From top to bottom
  for (int32 i = HEIGHT-1; i >= 0 ; i--)
  {
    for (int32 j = 0; j < WIDTH; j++)
    {
      vec3 backgroundColor = { 0.0, ((real32)i/HEIGHT), ((real32)j/WIDTH) };
      vec3 col = {};

      for (int32 samples = 0; samples < MAX_SAMPLES; samples++)
      {
        real32 u = real32(j + distribution(engine))/real32(WIDTH);
        real32 v = real32(i + distribution(engine))/real32(HEIGHT);

        ray cameraRay = {};
        cameraRay.origin = myScene.camera;
        cameraRay.direction = lowerLeftCorner + u*horizontalOffset + v*verticalOffset;

        vec3 tempCol = color(cameraRay, &myScene, backgroundColor, depth);
        clamp(&tempCol);
        col += tempCol;
      }

      col /= (real32)MAX_SAMPLES;

      int32 r = int32(255.0*col.e[0]);
      int32 g = int32(255.0*col.e[1]);
      int32 b = int32(255.0*col.e[2]);

      ofs << r << " " << g << " " << b << "\n";
    }
  }

  ofs.close();

  // Load the image
  surface = IMG_Load("image.ppm");
  if (surface == 0)
  {
    std::cout << "Error in IMG_Load(): " << IMG_GetError() << "\n";
  }

  texture = SDL_CreateTextureFromSurface(renderer, surface);
  if (texture == 0)
  {
    std::cout << "Error in SDL_CreateTextureFromSurface(): " << SDL_GetError() << "\n";
  }
  SDL_FreeSurface(surface);

  SDL_Event event;

  bool running = true;

  while (running)
  {
    while (SDL_PollEvent(&event))
    {
      if (event.type == SDL_QUIT)
      {
        running = false;
      }
      else if (event.type == SDL_KEYDOWN)
      {
        if (event.key.keysym.sym == SDLK_ESCAPE)
        {
          running = false;
        }
      }
    }

    // Show the texture
    SDL_RenderCopy(renderer, texture, 0, 0);
    SDL_RenderPresent(renderer);
  }

  // Free the texture
  SDL_DestroyTexture(texture);
  // Quit IMG
  IMG_Quit();
  // Quit SDL
  SDL_Quit();

  return(0);
}
<commit_msg>Ambient contribution should be added only once, not for every light!!! Fixed<commit_after>// TODO(ralntdir):
// Think how to clean SDL if the programs ends with some crash
// Finished the program if there is a problem at SDL/IMG init or
// when creating the window or the renderer
//
// Features to add:
// ray->sphere intersection (check if it's completed)
// shadows
// reflection
// read llc, hoffset and voffset from file

// Files manipulation
#include <iostream>
#include <fstream>
#include <string>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

// NOTE(ralntdir): For number types
#include <stdint.h>

// NOTE(ralntdir): For rand
#include <random>

// NOTE(ralntdir): For FLT_MAX
#include <float.h>

typedef int32_t int32;

typedef float real32;
typedef double real64;

// TODO(ralntdir): read this from a scene file?
#define WIDTH 500
#define HEIGHT 500
#define MAX_COLOR 255
#define MAX_SAMPLES 100
#define MAX_DEPTH 5

#include <math.h>
#include "myMath.h"

struct ray
{
  vec3 origin;
  vec3 direction;
};

struct sphere
{
  vec3 center;
  real32 radius;

  vec3 ka;
  vec3 kd;
  vec3 ks;

  vec3 kr;

  real32 alpha;
};

enum light_type
{
  point,
  directional,
};

struct light
{
  vec3 position;
  vec3 intensity;
  light_type type;
};

struct scene
{
  vec3 camera;
  vec3 ul;
  vec3 ur;
  vec3 lr;
  vec3 ll;

  int32 maxSpheres = 8;
  int32 maxLights = 2;

  int32 numSpheres;
  int32 numLights;
  light lights[2];
  sphere spheres[8];
};

bool hitSphere(sphere mySphere, ray myRay, real32 *t)
{
  bool result = false;

  vec3 originCenter = myRay.origin - mySphere.center;

  real32 a = dotProduct(myRay.direction, myRay.direction);
  real32 b = 2 * dotProduct(originCenter, myRay.direction);
  real32 c = dotProduct(originCenter, originCenter) - mySphere.radius*mySphere.radius;

  real32 discriminant = b*b - 4*a*c;

  if (discriminant < 0)
  {
    return(result);
  }
  else
  {
    result = true;

    real32 root1 = (-b + sqrt(discriminant))/(2*a);
    real32 root2 = (-b - sqrt(discriminant))/(2*a);

    if ((root1 < root2) && (root1 > 0.0))
    {
      *t = root1;
    }
    else if ((root2 < root1) && (root2 > 0.0))
    {
      *t = root2;
    }
    else if ((root1 < 0) && (root2 < 0))
    {
      result = false;
    }
  }

  return(result);
}

// TODO(ralntdir): add attenuation for point lights
// TODO(ralntdir): technically this is not Phong Shading
vec3 phongShading(light myLight, sphere mySphere, vec3 camera, vec3 hitPoint, real32 visible, int32 depth)
{
  vec3 result;

  // *N vector (normal at hit point)
  // *L vector (lightPosition - hitPoint)
  vec3 N = normalize(hitPoint - mySphere.center);
  vec3 L = {};
  if (myLight.type == point)
  {
    L = normalize(myLight.position - hitPoint);
  }
  else if (myLight.type == directional)
  {
    L = normalize(-myLight.position);
  }
  real32 dotProductLN = max(dotProduct(L, N), 0.0);
  real32 filterSpecular = dotProductLN > 0.0 ? 1.0 : 0.0;

  // *R vector (reflection of L -> 2(L·N)N - L)
  // *V vector (camera - hitPoint)
  vec3 R = normalize(2*dotProduct(L, N)*N - L);
  vec3 V = normalize(camera - hitPoint);

  // Only add specular component if you have diffuse,
  // if dotProductLN > 0.0
  // if (depth == -1)
  // {
  //   result = mySphere.ka*myLight.intensity +
  //            visible*mySphere.kd*myLight.intensity*dotProductLN +
  //            visible*filterSpecular*mySphere.ks*myLight.intensity*pow(max(dotProduct(R, V), 0.0), mySphere.alpha);
  // }
  // else if (depth > 1)
  // {
  result = visible*mySphere.kd*myLight.intensity*dotProductLN +
           visible*filterSpecular*mySphere.ks*myLight.intensity*pow(max(dotProduct(R, V), 0.0), mySphere.alpha);
  // }

  return(result);
}

ray getShadowRay(light myLight, vec3 hitPoint, vec3 normalAtHitPoint)
{
  ray result = {};

  // NOTE(ralntdir): delta to avoid shadow acne.
  real32 bias = 0.01;

  result.origin = hitPoint + normalAtHitPoint*bias;

  if (myLight.type == directional)
  {
    result.direction = normalize(-myLight.position);
  }
  else if (myLight.type == point)
  {
    result.direction = normalize(myLight.position - hitPoint);
  }

  return(result);
}

vec3 color(ray myRay, scene *myScene, vec3 backgroundColor, int32 depth)
{
  // vec3 result = backgroundColor;
  vec3 result = { 0.0, 0.0, 0.0 };

  if (depth <= MAX_DEPTH)
  {
    real32 maxt = FLT_MAX;
    real32 t = -1.0;

    for (int i = 0; i < myScene->numSpheres; i++)
    {
      sphere mySphere = myScene->spheres[i];
      if (hitSphere(mySphere, myRay, &t))
      {
        if ((t >= 0.0) && (t < maxt))
        {
          result = {};
          // NOTE(ralntdir): Let's suppose that ia is (1.0, 1.0, 1.0)
          result += mySphere.ka;
          maxt = t;
          vec3 hitPoint = myRay.origin + t*myRay.direction;

          vec3 N = normalize(hitPoint - mySphere.center);

          for (int j = 0; j < myScene->numLights; j++)
          {
            light myLight = myScene->lights[j];

            ray shadowRay = getShadowRay(myLight, hitPoint, N);

            real32 visible = 1.0;

            for (int k = 0; k < myScene->numSpheres; k++)
            {
              if (i != k)
              {
                sphere mySphere1 = myScene->spheres[k];
                real32 t1 = -1.0;
                if (hitSphere(mySphere1, shadowRay, &t1))
                {
                  visible = 0.0;
                  break;
                }
              }
            }
            result += phongShading(myLight, mySphere, myScene->camera, hitPoint, visible, depth);
          }

          // Add reflection
          ray reflectedRay = {};
          reflectedRay.origin = hitPoint + N*0.01;
          reflectedRay.direction = 2*dotProduct(-myRay.direction, N)*N + myRay.direction;

          result += mySphere.kr*color(reflectedRay, myScene, backgroundColor, depth+1);
        }
      }
    }
  }
  return(result);
}

void readSceneFile(scene *myScene, char *filename)
{
  std::string line;
  std::ifstream scene(filename);

  if (scene.is_open())
  {
    while (!scene.eof())
    {
      scene >> line;

      // If line is not a comment
      if (line[0] == '#')
      {
        std::getline(scene, line);
        std::cout << line << "\n";
      }
      else
      {
        std::cout << line << "\n";

        if (line == "camera")
        {
          scene >> myScene->camera.x;
          scene >> myScene->camera.y;
          scene >> myScene->camera.z;
        }
        else if (line == "sphere")
        {
          sphere mySphere = {};

          scene >> line; // center
          scene >> mySphere.center.x;
          scene >> mySphere.center.y;
          scene >> mySphere.center.z;
          scene >> line; // radius
          scene >> mySphere.radius;
          scene >> line; // ka
          scene >> mySphere.ka.x;
          scene >> mySphere.ka.y;
          scene >> mySphere.ka.z;
          scene >> line; // kd
          scene >> mySphere.kd.x;
          scene >> mySphere.kd.y;
          scene >> mySphere.kd.z;
          scene >> line; // ks
          scene >> mySphere.ks.x;
          scene >> mySphere.ks.y;
          scene >> mySphere.ks.z;
          scene >> line; // kr || alpha
          if (line == "kr")
          {
            scene >> mySphere.kr.x;
            scene >> mySphere.kr.y;
            scene >> mySphere.kr.z;
            scene >> line; // alpha
            scene >> mySphere.alpha;
          }
          else if (line == "alpha")
          {
            scene >> mySphere.alpha;
          }

          myScene->numSpheres++;
          if (myScene->numSpheres <= myScene->maxSpheres)
          {
            myScene->spheres[myScene->numSpheres-1] = mySphere;
          }
        }
        else if (line == "light")
        {
          light myLight = {};

          scene >> line; // position
          scene >> myLight.position.x;
          scene >> myLight.position.y;
          scene >> myLight.position.z;
          scene >> line; // intensity
          scene >> myLight.intensity.x;
          scene >> myLight.intensity.y;
          scene >> myLight.intensity.z;
          scene >> line; // type
          scene >> line;

          if (line.compare("point") == 0)
          {
            myLight.type = point;
          }
          else if (line.compare("directional") == 0)
          {
            myLight.type = directional;
          }

          myScene->numLights++;
          if (myScene->numLights <= myScene->maxLights)
          {
            myScene->lights[myScene->numLights-1] = myLight;
          }
        }
        else if (line == "ul")
        {
          vec3 ul = {};
          scene >> ul.x;
          scene >> ul.y;
          scene >> ul.z;

          myScene->ul = ul;
        }
        else if (line == "ur")
        {
          vec3 ur = {};
          scene >> ur.x;
          scene >> ur.y;
          scene >> ur.z;

          myScene->ur = ur;
        }
        else if (line == "lr")
        {
          vec3 lr = {};
          scene >> lr.x;
          scene >> lr.y;
          scene >> lr.z;

          myScene->lr = lr;
        }
        else if (line == "ll")
        {
          vec3 ll = {};
          scene >> ll.x;
          scene >> ll.y;
          scene >> ll.z;

          myScene->ll = ll;
        }
      }
    }
    scene.close();
  }
  else
  {
    std::cout << "There was a problem opening the scene file\n";
  }
}

int main(int argc, char* argv[])
{
  SDL_Window *window;
  SDL_Renderer *renderer;
  SDL_Surface *surface;
  SDL_Texture *texture;

  if (argc < 2)
  {
    std::cout << "Missing scene file. Usage: ./program sceneFile\n";
    return(1);
  }
  char *sceneFileName = argv[1];

  // Init SDL
  if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  {
    std::cout << "Error in SDL_Init(): " << SDL_GetError() << "\n";
  }

  // Init SDL_Image
  if (IMG_Init(0) < 0)
  {
    std::cout << "Error in IMG_Init(): " << IMG_GetError() << "\n";
  }

  // Create a Window
  // NOTE(ralntdir): SDL_WINDOW_SHOWN is ignored by SDL_CreateWindow().
  // The SDL_Window is implicitly shown if SDL_WINDOW_HIDDEN is not set.
  window = SDL_CreateWindow("Devember RT", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
                            WIDTH, HEIGHT, SDL_WINDOW_SHOWN);

  if (window == 0)
  {
    std::cout << "Error in SDL_CreateWindow(): " << SDL_GetError() << "\n";
  }

  // Create a Renderer
  renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  if (renderer == 0)
  {
    std::cout << "Error in SDL_CreateRenderer(): " << SDL_GetError() << "\n";
  }

  scene myScene = {};
  // Read scene file
  readSceneFile(&myScene, sceneFileName);

  // Create a .ppm file
  std::ofstream ofs("image.ppm", std::ofstream::out | std::ofstream::binary);

  ofs << "P3\n";
  ofs << "# image.ppm\n";
  ofs << WIDTH << " " << HEIGHT << "\n";
  ofs << MAX_COLOR << "\n";

  vec3 horizontalOffset = myScene.ur - myScene.ul;
  vec3 verticalOffset = myScene.ul - myScene.ll;
  vec3 lowerLeftCorner = myScene.ll;

  // NOTE(ralntdir): generates random unsigned integers
  std::default_random_engine engine;
  // NOTE(ralntdir): generates random floats between [0, 1)
  std::uniform_real_distribution<real32> distribution(0, 1);

  int32 depth = 1;

  // NOTE(ralntdir): From top to bottom
  for (int32 i = HEIGHT-1; i >= 0 ; i--)
  {
    for (int32 j = 0; j < WIDTH; j++)
    {
      vec3 backgroundColor = { 0.0, ((real32)i/HEIGHT), ((real32)j/WIDTH) };
      vec3 col = {};

      for (int32 samples = 0; samples < MAX_SAMPLES; samples++)
      {
        real32 u = real32(j + distribution(engine))/real32(WIDTH);
        real32 v = real32(i + distribution(engine))/real32(HEIGHT);

        ray cameraRay = {};
        cameraRay.origin = myScene.camera;
        cameraRay.direction = lowerLeftCorner + u*horizontalOffset + v*verticalOffset;

        vec3 tempCol = color(cameraRay, &myScene, backgroundColor, depth);
        clamp(&tempCol);
        col += tempCol;
      }

      col /= (real32)MAX_SAMPLES;

      int32 r = int32(255.0*col.e[0]);
      int32 g = int32(255.0*col.e[1]);
      int32 b = int32(255.0*col.e[2]);

      ofs << r << " " << g << " " << b << "\n";
    }
  }

  ofs.close();

  // Load the image
  surface = IMG_Load("image.ppm");
  if (surface == 0)
  {
    std::cout << "Error in IMG_Load(): " << IMG_GetError() << "\n";
  }

  texture = SDL_CreateTextureFromSurface(renderer, surface);
  if (texture == 0)
  {
    std::cout << "Error in SDL_CreateTextureFromSurface(): " << SDL_GetError() << "\n";
  }
  SDL_FreeSurface(surface);

  SDL_Event event;

  bool running = true;

  while (running)
  {
    while (SDL_PollEvent(&event))
    {
      if (event.type == SDL_QUIT)
      {
        running = false;
      }
      else if (event.type == SDL_KEYDOWN)
      {
        if (event.key.keysym.sym == SDLK_ESCAPE)
        {
          running = false;
        }
      }
    }

    // Show the texture
    SDL_RenderCopy(renderer, texture, 0, 0);
    SDL_RenderPresent(renderer);
  }

  // Free the texture
  SDL_DestroyTexture(texture);
  // Quit IMG
  IMG_Quit();
  // Quit SDL
  SDL_Quit();

  return(0);
}
<|endoftext|>


<commit_before>/***********************************************************************
 row.cpp - Implements the Row class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "row.h"
#include "result.h"
#include "exceptions.h"

namespace mysqlpp {

Row::size_type Row::size() const
{
	return res->num_fields();
}

const ColData Row::operator[] (size_type i) const
{
	if (!initialized) {
		if (throw_exceptions)
			throw BadQuery("Row not initialized");
		else
			return ColData();
	}

	return ColData(data.at(i).c_str(), res->types(i), is_nulls[i]);
}

const ColData Row::lookup_by_name(const char* i) const
{
	int si = res->field_num(std::string(i));
	if (si < res->num_fields()) {
		return (*this)[si];
	}
	else {
		throw BadFieldName(i);
	}
}

} // end namespace mysqlpp

<commit_msg>Whitespace change<commit_after>/***********************************************************************
 row.cpp - Implements the Row class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "row.h"
#include "result.h"
#include "exceptions.h"

namespace mysqlpp {

Row::size_type Row::size() const
{
	return res->num_fields();
}

const ColData Row::operator [](size_type i) const
{
	if (!initialized) {
		if (throw_exceptions)
			throw BadQuery("Row not initialized");
		else
			return ColData();
	}

	return ColData(data.at(i).c_str(), res->types(i), is_nulls[i]);
}

const ColData Row::lookup_by_name(const char* i) const
{
	int si = res->field_num(std::string(i));
	if (si < res->num_fields()) {
		return (*this)[si];
	}
	else {
		throw BadFieldName(i);
	}
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>// Copyright © 2018 Dmitriy Khaustov
//
// 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.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.10.08

// MysqlRow.hpp

#pragma once

#include <mysql.h>
#include "../DbRow.hpp"
#include <type_traits>
#include <string>

class MysqlRow final : public DbRow
{
private:
	MYSQL_ROW _data;

public:
	MysqlRow(MysqlRow&&) noexcept = delete; // Move-constructor
	MysqlRow(const MysqlRow&) = delete; // Copy-constructor
	MysqlRow& operator=(MysqlRow&&) noexcept = delete; // Move-assignment
	MysqlRow& operator=(MysqlRow const&) = delete; // Copy-assignment

	MysqlRow() // Default-constructor
	: _data(nullptr)
	{
	}

	virtual ~MysqlRow() override = default; // Destructor

	void set(MYSQL_ROW value)
	{
		_data = value;
	}

	MYSQL_ROW get()
	{
		return _data;
	}

	class FieldValue final
	{
	private:
		const char * const _data;

	public:
		FieldValue(const char *const data): _data(data) {}

		template<typename T, typename std::enable_if<std::is_integral<T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_integral<T>::value, bool>::type detect();
			return static_cast<T>(_data ? std::atoll(_data) : 0);
		}

		template<typename T, typename std::enable_if<std::is_floating_point<T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_floating_point<T>::value, bool>::type detect();
			return static_cast<T>(_data ? std::atof(_data) : 0);
		}

		template<typename T, typename std::enable_if<std::is_same<std::string, T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_same<std::string, T>::value, void>::type detect();
			return T(_data ? _data : "");
		}
	};

	FieldValue operator[](size_t index) const
	{
		return _data[index];
	}
};
<commit_msg>Little improve MysqlRow class<commit_after>// Copyright © 2018 Dmitriy Khaustov
//
// 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.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.10.08

// MysqlRow.hpp

#pragma once

#include <mysql.h>
#include "../DbRow.hpp"
#include <type_traits>
#include <string>

class MysqlRow final : public DbRow
{
private:
	MYSQL_ROW _data;

public:
	MysqlRow(MysqlRow&&) noexcept = delete; // Move-constructor
	MysqlRow(const MysqlRow&) = delete; // Copy-constructor
	MysqlRow& operator=(MysqlRow&&) noexcept = delete; // Move-assignment
	MysqlRow& operator=(MysqlRow const&) = delete; // Copy-assignment

	MysqlRow() // Default-constructor
	: _data(nullptr)
	{
	}

	~MysqlRow() override = default; // Destructor

	void set(MYSQL_ROW value)
	{
		_data = value;
	}

	MYSQL_ROW get()
	{
		return _data;
	}

	class FieldValue final
	{
	private:
		const char * const _data;

	public:
		FieldValue(const char *const data): _data(data) {}

		bool isNull() const
		{
			return _data == nullptr;
		}

		template<typename T, typename std::enable_if<std::is_integral<T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_integral<T>::value, bool>::type detect();
			return static_cast<T>(_data ? std::atoll(_data) : 0);
		}

		template<typename T, typename std::enable_if<std::is_floating_point<T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_floating_point<T>::value, bool>::type detect();
			return static_cast<T>(_data ? std::atof(_data) : 0);
		}

		template<typename T, typename std::enable_if<std::is_same<std::string, T>::value, void>::type* = nullptr>
		operator T() const
		{
			typename std::enable_if<std::is_same<std::string, T>::value, void>::type detect();
			return T(_data ? _data : "");
		}
	};

	FieldValue operator[](size_t index) const
	{
		return _data[index];
	}
};
<|endoftext|>


<commit_before>#pragma once

class local_datagram_client final {
public:
  local_datagram_client(const char* _Nonnull path) : endpoint_(path),
                                                     io_service_(),
                                                     work_(io_service_),
                                                     socket_(io_service_) {
    socket_.open();
    thread_ = std::thread([this] { (this->io_service_).run(); });
  }

  ~local_datagram_client(void) {
    io_service_.post(boost::bind(&local_datagram_client::do_stop, this));
    thread_.join();
  }

  void send_to(const uint8_t* _Nonnull p, size_t length) {
    auto ptr = std::make_shared<buffer>(p, length);
    io_service_.post(boost::bind(&local_datagram_client::do_send, this, ptr));
  }

private:
  class buffer final {
  public:
    buffer(const uint8_t* _Nonnull p, size_t length) {
      v_.resize(length);
      memcpy(&(v_[0]), p, length);
    }

    const std::vector<uint8_t>& get_vector(void) const { return v_; }

  private:
    std::vector<uint8_t> v_;
  };

  void do_send(const std::shared_ptr<buffer>& ptr) {
    socket_.async_send_to(boost::asio::buffer(ptr->get_vector()), endpoint_,
                          boost::bind(&local_datagram_client::handle_send, this, ptr));
  }

  void handle_send(const std::shared_ptr<buffer>& ptr) {
    // buffer will be released.
  }

  void do_stop(void) {
    io_service_.stop();
  }

  boost::asio::local::datagram_protocol::endpoint endpoint_;
  boost::asio::io_service io_service_;
  boost::asio::io_service::work work_;
  boost::asio::local::datagram_protocol::socket socket_;
  std::thread thread_;
};
<commit_msg>change send_to args<commit_after>#pragma once

class local_datagram_client final {
public:
  local_datagram_client(const char* _Nonnull path) : endpoint_(path),
                                                     io_service_(),
                                                     work_(io_service_),
                                                     socket_(io_service_) {
    socket_.open();
    thread_ = std::thread([this] { (this->io_service_).run(); });
  }

  ~local_datagram_client(void) {
    io_service_.post(boost::bind(&local_datagram_client::do_stop, this));
    thread_.join();
  }

  void send_to(const std::vector<uint8_t>& v) {
    auto ptr = std::make_shared<buffer>(v);
    io_service_.post(boost::bind(&local_datagram_client::do_send, this, ptr));
  }

private:
  class buffer final {
  public:
    buffer(const std::vector<uint8_t> v) {
      v_ = v;
    }

    buffer(const uint8_t* _Nonnull p, size_t length) {
      v_.resize(length);
      memcpy(&(v_[0]), p, length);
    }

    const std::vector<uint8_t>& get_vector(void) const { return v_; }

  private:
    std::vector<uint8_t> v_;
  };

  void do_send(const std::shared_ptr<buffer>& ptr) {
    socket_.async_send_to(boost::asio::buffer(ptr->get_vector()), endpoint_,
                          boost::bind(&local_datagram_client::handle_send, this, ptr));
  }

  void handle_send(const std::shared_ptr<buffer>& ptr) {
    // buffer will be released.
  }

  void do_stop(void) {
    io_service_.stop();
  }

  boost::asio::local::datagram_protocol::endpoint endpoint_;
  boost::asio::io_service io_service_;
  boost::asio::io_service::work work_;
  boost::asio::local::datagram_protocol::socket socket_;
  std::thread thread_;
};
<|endoftext|>