<commit_before>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef INGEN_CLIENT_BLOCKMODEL_HPP
#define INGEN_CLIENT_BLOCKMODEL_HPP

#include <cstdlib>
#include <string>
#include <vector>

#include "raul/SharedPtr.hpp"
#include "ingen/Node.hpp"
#include "ingen/client/ObjectModel.hpp"
#include "ingen/client/PluginModel.hpp"
#include "ingen/client/PortModel.hpp"

namespace Raul { class Path; }

namespace Ingen {

class URIs;

namespace Client {

class PluginModel;
class ClientStore;

/** Block model class, used by the client to store engine's state.
 *
 * @ingroup IngenClient
 */
class BlockModel : public ObjectModel
{
public:
	BlockModel(const BlockModel& copy);
	virtual ~BlockModel();

	GraphType graph_type() const { return Node::GRAPH; }

	typedef std::vector< SharedPtr<const PortModel> > Ports;

	SharedPtr<const PortModel> get_port(const Raul::Symbol& symbol) const;

	Node* port(uint32_t index) const;

	const Raul::URI&       plugin_uri()   const { return _plugin_uri; }
	const Plugin*          plugin()       const { return _plugin.get(); }
	Plugin*                plugin()             { return _plugin.get(); }
	SharedPtr<PluginModel> plugin_model() const { return _plugin; }
	uint32_t               num_ports()    const { return _ports.size(); }
	const Ports&           ports()        const { return _ports; }

	void default_port_value_range(SharedPtr<const PortModel> port,
	                              float& min, float& max, uint32_t srate=1) const;

	void port_value_range(SharedPtr<const PortModel> port,
	                      float& min, float& max, uint32_t srate=1) const;

	std::string label() const;
	std::string port_label(SharedPtr<const PortModel> port) const;

	// Signals
	INGEN_SIGNAL(new_port, void, SharedPtr<const PortModel>);
	INGEN_SIGNAL(removed_port, void, SharedPtr<const PortModel>);

protected:
	friend class ClientStore;

	BlockModel(URIs&             uris,
	           const Raul::URI&  plugin_uri,
	           const Raul::Path& path);
	BlockModel(URIs&                  uris,
	           SharedPtr<PluginModel> plugin,
	           const Raul::Path&      path);
	explicit BlockModel(const Raul::Path& path);

	void add_child(SharedPtr<ObjectModel> c);
	bool remove_child(SharedPtr<ObjectModel> c);
	void add_port(SharedPtr<PortModel> pm);
	void remove_port(SharedPtr<PortModel> pm);
	void remove_port(const Raul::Path& port_path);
	void set(SharedPtr<ObjectModel> model);

	virtual void clear();

	Ports                  _ports; ///< Vector of ports
	Raul::URI              _plugin_uri; ///< Plugin URI (if PluginModel is unknown)
	SharedPtr<PluginModel> _plugin; ///< The plugin this block is an instance of

private:
	mutable uint32_t _num_values; ///< Size of _min_values and _max_values
	mutable float*   _min_values; ///< Port min values (cached for LV2)
	mutable float*   _max_values; ///< Port max values (cached for LV2)
};

} // namespace Client
} // namespace Ingen

#endif // INGEN_CLIENT_BLOCKMODEL_HPP
<commit_msg>Fix graph_type of BlockModel (fix copy and paste).<commit_after>/*
  This file is part of Ingen.
  Copyright 2007-2012 David Robillard <http://drobilla.net/>

  Ingen is free software: you can redistribute it and/or modify it under the
  terms of the GNU Affero General Public License as published by the Free
  Software Foundation, either version 3 of the License, or any later version.

  Ingen 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 Affero General Public License for details.

  You should have received a copy of the GNU Affero General Public License
  along with Ingen.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef INGEN_CLIENT_BLOCKMODEL_HPP
#define INGEN_CLIENT_BLOCKMODEL_HPP

#include <cstdlib>
#include <string>
#include <vector>

#include "raul/SharedPtr.hpp"
#include "ingen/Node.hpp"
#include "ingen/client/ObjectModel.hpp"
#include "ingen/client/PluginModel.hpp"
#include "ingen/client/PortModel.hpp"

namespace Raul { class Path; }

namespace Ingen {

class URIs;

namespace Client {

class PluginModel;
class ClientStore;

/** Block model class, used by the client to store engine's state.
 *
 * @ingroup IngenClient
 */
class BlockModel : public ObjectModel
{
public:
	BlockModel(const BlockModel& copy);
	virtual ~BlockModel();

	GraphType graph_type() const { return Node::BLOCK; }

	typedef std::vector< SharedPtr<const PortModel> > Ports;

	SharedPtr<const PortModel> get_port(const Raul::Symbol& symbol) const;

	Node* port(uint32_t index) const;

	const Raul::URI&       plugin_uri()   const { return _plugin_uri; }
	const Plugin*          plugin()       const { return _plugin.get(); }
	Plugin*                plugin()             { return _plugin.get(); }
	SharedPtr<PluginModel> plugin_model() const { return _plugin; }
	uint32_t               num_ports()    const { return _ports.size(); }
	const Ports&           ports()        const { return _ports; }

	void default_port_value_range(SharedPtr<const PortModel> port,
	                              float& min, float& max, uint32_t srate=1) const;

	void port_value_range(SharedPtr<const PortModel> port,
	                      float& min, float& max, uint32_t srate=1) const;

	std::string label() const;
	std::string port_label(SharedPtr<const PortModel> port) const;

	// Signals
	INGEN_SIGNAL(new_port, void, SharedPtr<const PortModel>);
	INGEN_SIGNAL(removed_port, void, SharedPtr<const PortModel>);

protected:
	friend class ClientStore;

	BlockModel(URIs&             uris,
	           const Raul::URI&  plugin_uri,
	           const Raul::Path& path);
	BlockModel(URIs&                  uris,
	           SharedPtr<PluginModel> plugin,
	           const Raul::Path&      path);
	explicit BlockModel(const Raul::Path& path);

	void add_child(SharedPtr<ObjectModel> c);
	bool remove_child(SharedPtr<ObjectModel> c);
	void add_port(SharedPtr<PortModel> pm);
	void remove_port(SharedPtr<PortModel> pm);
	void remove_port(const Raul::Path& port_path);
	void set(SharedPtr<ObjectModel> model);

	virtual void clear();

	Ports                  _ports; ///< Vector of ports
	Raul::URI              _plugin_uri; ///< Plugin URI (if PluginModel is unknown)
	SharedPtr<PluginModel> _plugin; ///< The plugin this block is an instance of

private:
	mutable uint32_t _num_values; ///< Size of _min_values and _max_values
	mutable float*   _min_values; ///< Port min values (cached for LV2)
	mutable float*   _max_values; ///< Port max values (cached for LV2)
};

} // namespace Client
} // namespace Ingen

#endif // INGEN_CLIENT_BLOCKMODEL_HPP
<|endoftext|>


<commit_before>/*

Copyright (c) 2011, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/disk_io_job.hpp"
#include "libtorrent/storage.hpp"

namespace libtorrent
{
	disk_io_job::disk_io_job()
		: buffer(0)
		, requester(0)
		, piece(0)
		, action(read)
		, ret(0)
		, flags(0)
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
		, in_use(false)
		, callback_called(false)
#endif
	{
		d.io.offset = 0;
		d.io.buffer_size = 0;
		d.io.max_cache_line = 0;
	}

	disk_io_job::~disk_io_job()
	{
		if (action == rename_file || action == move_storage)
			free(buffer);
		if (action == save_resume_data)
			delete (entry*)buffer;
	}

	bool is_job_immediate(int type)
	{
		return type == disk_io_job::get_cache_info
			|| type == disk_io_job::update_settings
			|| type == disk_io_job::aiocb_complete
			|| type == disk_io_job::sync_piece;
	}
}

<commit_msg>make hash_complete also circumvent fences, to prevent dead-locks<commit_after>/*

Copyright (c) 2011, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/disk_io_job.hpp"
#include "libtorrent/storage.hpp"

namespace libtorrent
{
	disk_io_job::disk_io_job()
		: buffer(0)
		, requester(0)
		, piece(0)
		, action(read)
		, ret(0)
		, flags(0)
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
		, in_use(false)
		, callback_called(false)
#endif
	{
		d.io.offset = 0;
		d.io.buffer_size = 0;
		d.io.max_cache_line = 0;
	}

	disk_io_job::~disk_io_job()
	{
		if (action == rename_file || action == move_storage)
			free(buffer);
		if (action == save_resume_data)
			delete (entry*)buffer;
	}

	bool is_job_immediate(int type)
	{
		return type == disk_io_job::get_cache_info
			|| type == disk_io_job::update_settings
			|| type == disk_io_job::aiocb_complete
			|| type == disk_io_job::hash_complete
			|| type == disk_io_job::sync_piece;
	}
}

<|endoftext|>


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

#include "base/trace.hh"
#include "cpu/static_inst.hh"

namespace ArmISA
{
class ArmStaticInst : public StaticInst
{
  protected:
    int32_t shift_rm_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    int32_t shift_rm_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool shift_carry_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    bool shift_carry_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool arm_add_carry(int32_t result, int32_t lhs, int32_t rhs) const;
    bool arm_sub_carry(int32_t result, int32_t lhs, int32_t rhs) const;

    bool arm_add_overflow(int32_t result, int32_t lhs, int32_t rhs) const;
    bool arm_sub_overflow(int32_t result, int32_t lhs, int32_t rhs) const;

    // Constructor
    ArmStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass)
        : StaticInst(mnem, _machInst, __opClass)
    {
    }

    /// Print a register name for disassembly given the unique
    /// dependence tag number (FP or int).
    void printReg(std::ostream &os, int reg) const;
    void printMnemonic(std::ostream &os,
                       const std::string &suffix = "",
                       bool withPred = true) const;
    void printMemSymbol(std::ostream &os, const SymbolTable *symtab,
                        const std::string &prefix, const Addr addr,
                        const std::string &suffix) const;
    void printShiftOperand(std::ostream &os) const;

    void printDataInst(std::ostream &os, bool withImm) const;

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
}

#endif //__ARCH_ARM_INSTS_STATICINST_HH__
<commit_msg>ARM: Write some functions to write to the CPSR and SPSR for instructions.<commit_after>/* Copyright (c) 2007-2008 The Florida State University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Stephen Hines
 */
#ifndef __ARCH_ARM_INSTS_STATICINST_HH__
#define __ARCH_ARM_INSTS_STATICINST_HH__

#include "base/trace.hh"
#include "cpu/static_inst.hh"

namespace ArmISA
{
class ArmStaticInst : public StaticInst
{
  protected:
    int32_t shift_rm_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    int32_t shift_rm_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool shift_carry_imm(uint32_t base, uint32_t shamt,
                         uint32_t type, uint32_t cfval) const;
    bool shift_carry_rs(uint32_t base, uint32_t shamt,
                        uint32_t type, uint32_t cfval) const;

    bool arm_add_carry(int32_t result, int32_t lhs, int32_t rhs) const;
    bool arm_sub_carry(int32_t result, int32_t lhs, int32_t rhs) const;

    bool arm_add_overflow(int32_t result, int32_t lhs, int32_t rhs) const;
    bool arm_sub_overflow(int32_t result, int32_t lhs, int32_t rhs) const;

    // Constructor
    ArmStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass)
        : StaticInst(mnem, _machInst, __opClass)
    {
    }

    /// Print a register name for disassembly given the unique
    /// dependence tag number (FP or int).
    void printReg(std::ostream &os, int reg) const;
    void printMnemonic(std::ostream &os,
                       const std::string &suffix = "",
                       bool withPred = true) const;
    void printMemSymbol(std::ostream &os, const SymbolTable *symtab,
                        const std::string &prefix, const Addr addr,
                        const std::string &suffix) const;
    void printShiftOperand(std::ostream &os) const;

    void printDataInst(std::ostream &os, bool withImm) const;

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;

    static uint32_t
    cpsrWriteByInstr(CPSR cpsr, uint32_t val,
            uint8_t byteMask, bool affectState)
    {
        bool privileged = (cpsr.mode != MODE_USER);

        uint32_t bitMask = 0;

        if (bits(byteMask, 3)) {
            unsigned lowIdx = affectState ? 24 : 27;
            bitMask = bitMask | mask(31, lowIdx);
        }
        if (bits(byteMask, 2)) {
            bitMask = bitMask | mask(19, 16);
        }
        if (bits(byteMask, 1)) {
            unsigned highIdx = affectState ? 15 : 9;
            unsigned lowIdx = privileged ? 8 : 9;
            bitMask = bitMask | mask(highIdx, lowIdx);
        }
        if (bits(byteMask, 0)) {
            if (privileged) {
                bitMask = bitMask | mask(7, 6);
                bitMask = bitMask | mask(5);
            }
            if (affectState)
                bitMask = bitMask | (1 << 5);
        }

        return ((uint32_t)cpsr & ~bitMask) | (val & bitMask);
    }

    static uint32_t
    spsrWriteByInstr(uint32_t spsr, uint32_t val,
            uint8_t byteMask, bool affectState)
    {
        uint32_t bitMask = 0;

        if (bits(byteMask, 3))
            bitMask = bitMask | mask(31, 24);
        if (bits(byteMask, 2))
            bitMask = bitMask | mask(19, 16);
        if (bits(byteMask, 1))
            bitMask = bitMask | mask(15, 8);
        if (bits(byteMask, 0))
            bitMask = bitMask | mask(7, 0);

        return ((spsr & ~bitMask) | (val & bitMask));
    }
};
}

#endif //__ARCH_ARM_INSTS_STATICINST_HH__
<|endoftext|>


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

#include "transpiler/tfhe_transpiler.h"

#include <string>
#include <utility>

#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "transpiler/common_transpiler.h"
#include "xls/common/status/status_macros.h"
#include "xls/contrib/xlscc/metadata_output.pb.h"
#include "xls/ir/function.h"
#include "xls/ir/node.h"
#include "xls/ir/node_iterator.h"
#include "xls/ir/nodes.h"
#include "xls/public/value.h"

namespace xls {
class Node;
}  // namespace xls

namespace fully_homomorphic_encryption {
namespace transpiler {

namespace {

using xls::Bits;
using xls::Function;
using xls::Literal;
using xls::Node;
using xls::Op;
using xls::Param;

std::string NodeReference(const Node* node) {
  return absl::StrFormat("temp_nodes[%d]", node->id());
}

std::string ParamBitReference(const Node* param, int offset) {
  int64_t param_bits = param->GetType()->GetFlatBitCount();
  if (param_bits == 1) {
    if (param->Is<xls::TupleIndex>() || param->Is<xls::ArrayIndex>()) {
      return param->operand(0)->GetName();
    }
  }
  return absl::StrFormat("&%s[%d]", param->GetName(), offset);
}

std::string OutputBitReference(absl::string_view output_arg, int offset) {
  return absl::StrFormat("&%s[%d]", output_arg, offset);
}

std::string CopyTo(absl::string_view destination, absl::string_view source) {
  return absl::Substitute("  bootsCOPY($0, $1, bk);\n", destination, source);
}

}  // namespace

// Input: "result", 0, Node(id = 3)
// Output: result[0] = temp_nodes[3];
std::string TfheTranspiler::CopyNodeToOutput(absl::string_view output_arg,
                                             int offset,
                                             const xls::Node* node) {
  return CopyTo(OutputBitReference(output_arg, offset), NodeReference(node));
}

// Input: Node(id = 4), Param("some_param"), 3
// Output: temp_nodes[4] = &some_param[3];
std::string TfheTranspiler::CopyParamToNode(const xls::Node* node,
                                            const xls::Node* param,
                                            int offset) {
  return CopyTo(NodeReference(node), ParamBitReference(param, offset));
}

// Input: Node(id = 5)
// Output: temp_nodes[5] = new new_gate_bootstrapping_ciphertext(bk->params);
std::string TfheTranspiler::InitializeNode(const Node* node) {
  return absl::Substitute(
      "  $0 = new_gate_bootstrapping_ciphertext(bk->params);\n",
      NodeReference(node));
}

// Input: Node(id = 5, op = kNot, operands = Node(id = 2))
// Output: "  bootsNOT(temp_nodes[5], temp_nodes[2], bk);\n\n"
absl::StatusOr<std::string> TfheTranspiler::Execute(const Node* node) {
  static const absl::flat_hash_map<xls::Op, absl::string_view> kFHEOps = {
      {Op::kAnd, "bootsAND"},
      {Op::kOr, "bootsOR"},
      {Op::kNot, "bootsNOT"},
      {Op::kLiteral, "bootsCONSTANT"},
  };
  auto it = kFHEOps.find(node->op());
  if (it == kFHEOps.end()) {
    return absl::InvalidArgumentError("Unsupported Op kind.");
  }
  const absl::string_view tfhe_op = it->second;

  std::string operation =
      absl::StrFormat("  %s(%s, ", tfhe_op, NodeReference(node));
  if (node->Is<Literal>()) {
    const Literal* literal = node->As<Literal>();
    XLS_ASSIGN_OR_RETURN(const Bits bit, literal->value().GetBitsWithStatus());
    if (bit.IsOne()) {
      absl::StrAppend(&operation, "1, ");
    } else if (bit.IsZero()) {
      absl::StrAppend(&operation, "0, ");
    } else {
      // We allow literals strictly for pulling values out of [param] arrays.
      for (const Node* user : literal->users()) {
        if (!user->Is<xls::ArrayIndex>()) {
          return absl::InvalidArgumentError("Unsupported literal value.");
        }
      }
      return "";
    }
  } else {
    for (const Node* operand_node : node->operands()) {
      absl::StrAppend(&operation, NodeReference(operand_node), ", ");
    }
  }
  // bk is the bootstrapping key from TFHE library.
  absl::StrAppend(&operation, "bk);\n\n");
  return operation;
}

absl::StatusOr<std::string> TfheTranspiler::TranslateHeader(
    const xls::Function* function,
    const xlscc_metadata::MetadataOutput& metadata,
    absl::string_view header_path) {
  XLS_ASSIGN_OR_RETURN(const std::string header_guard,
                       PathToHeaderGuard(header_path));
  static constexpr absl::string_view kHeaderTemplate =
      R"(#ifndef $2
#define $2

// clang-format off
#include "$3"
// clang-format on
#include "absl/status/status.h"
#include "absl/types/span.h"
#include "tfhe/tfhe.h"
#include "tfhe/tfhe_io.h"
#include "transpiler/data/tfhe_data.h"

$0;

$1#endif  // $2
)";
  XLS_ASSIGN_OR_RETURN(std::string signature,
                       FunctionSignature(function, metadata));
  absl::optional<std::string> typed_overload =
      TypedOverload(metadata, "Tfhe", "absl::Span<LweSample>",
                    "const TFheGateBootstrappingCloudKeySet*");
  return absl::Substitute(kHeaderTemplate, signature,
                          typed_overload.value_or(""), header_guard,
                          GetTypeHeader(header_path));
}

absl::StatusOr<std::string> TfheTranspiler::FunctionSignature(
    const Function* function, const xlscc_metadata::MetadataOutput& metadata) {
  return transpiler::FunctionSignature(
      metadata, "LweSample", "const TFheGateBootstrappingCloudKeySet*", "bk");
}

absl::StatusOr<std::string> TfheTranspiler::Prelude(
    const Function* function, const xlscc_metadata::MetadataOutput& metadata) {
  // $0: function name
  // $1: non-key parameter string
  static constexpr absl::string_view kPrelude =
      R"(#include <unordered_map>

#include "absl/status/status.h"
#include "absl/types/span.h"
#include "tfhe/tfhe.h"
#include "tfhe/tfhe_io.h"

$0 {
  std::unordered_map<int, LweSample*> temp_nodes;

)";
  XLS_ASSIGN_OR_RETURN(std::string signature,
                       FunctionSignature(function, metadata));
  return absl::Substitute(kPrelude, signature);
}

absl::StatusOr<std::string> TfheTranspiler::Conclusion() {
  return R"(  for (auto pair : temp_nodes) {
    delete_gate_bootstrapping_ciphertext(pair.second);
  }
  return absl::OkStatus();
}
)";
}

}  // namespace transpiler
}  // namespace fully_homomorphic_encryption
<commit_msg>Leverage `absl::ParsedFormat` for TFHE code generation.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "transpiler/tfhe_transpiler.h"

#include <string>
#include <utility>

#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "transpiler/common_transpiler.h"
#include "xls/common/status/status_macros.h"
#include "xls/contrib/xlscc/metadata_output.pb.h"
#include "xls/ir/function.h"
#include "xls/ir/node.h"
#include "xls/ir/node_iterator.h"
#include "xls/ir/nodes.h"
#include "xls/public/value.h"

namespace xls {
class Node;
}  // namespace xls

namespace fully_homomorphic_encryption {
namespace transpiler {

namespace {

using xls::Bits;
using xls::Function;
using xls::Literal;
using xls::Node;
using xls::Op;
using xls::Param;

std::string NodeReference(const Node* node) {
  return absl::StrFormat("temp_nodes[%d]", node->id());
}

std::string ParamBitReference(const Node* param, int offset) {
  int64_t param_bits = param->GetType()->GetFlatBitCount();
  if (param_bits == 1) {
    if (param->Is<xls::TupleIndex>() || param->Is<xls::ArrayIndex>()) {
      return param->operand(0)->GetName();
    }
  }
  return absl::StrFormat("&%s[%d]", param->GetName(), offset);
}

std::string OutputBitReference(absl::string_view output_arg, int offset) {
  return absl::StrFormat("&%s[%d]", output_arg, offset);
}

std::string CopyTo(absl::string_view destination, absl::string_view source) {
  return absl::Substitute("  bootsCOPY($0, $1, bk);\n", destination, source);
}

}  // namespace

// Input: "result", 0, Node(id = 3)
// Output: result[0] = temp_nodes[3];
std::string TfheTranspiler::CopyNodeToOutput(absl::string_view output_arg,
                                             int offset,
                                             const xls::Node* node) {
  return CopyTo(OutputBitReference(output_arg, offset), NodeReference(node));
}

// Input: Node(id = 4), Param("some_param"), 3
// Output: temp_nodes[4] = &some_param[3];
std::string TfheTranspiler::CopyParamToNode(const xls::Node* node,
                                            const xls::Node* param,
                                            int offset) {
  return CopyTo(NodeReference(node), ParamBitReference(param, offset));
}

// Input: Node(id = 5)
// Output: temp_nodes[5] = new new_gate_bootstrapping_ciphertext(bk->params);
std::string TfheTranspiler::InitializeNode(const Node* node) {
  return absl::Substitute(
      "  $0 = new_gate_bootstrapping_ciphertext(bk->params);\n",
      NodeReference(node));
}

// Input: Node(id = 5, op = kNot, operands = Node(id = 2))
// Output: "  bootsNOT(temp_nodes[5], temp_nodes[2], bk);\n\n"
absl::StatusOr<std::string> TfheTranspiler::Execute(const Node* node) {
  absl::ParsedFormat<'s', 's'> statement{
      "// Unsupported Op kind; arguments \"%s\", \"%s\"\n\n"};
  switch (node->op()) {
    case Op::kAnd:
      statement = absl::ParsedFormat<'s', 's'>{"  bootsAND(%s, %s, bk);\n\n"};
      break;
    case Op::kOr:
      statement = absl::ParsedFormat<'s', 's'>{"  bootsOR(%s, %s, bk);\n\n"};
      break;
    case Op::kNot:
      statement = absl::ParsedFormat<'s', 's'>{"  bootsNOT(%s, %s, bk);\n\n"};
      break;
    case Op::kLiteral:
      statement =
          absl::ParsedFormat<'s', 's'>{"  bootsCONSTANT(%s, %s, bk);\n\n"};
      break;
    default:
      return absl::InvalidArgumentError("Unsupported Op kind.");
  }

  std::vector<std::string> arguments;
  if (node->Is<Literal>()) {
    const Literal* literal = node->As<Literal>();
    XLS_ASSIGN_OR_RETURN(const Bits bit, literal->value().GetBitsWithStatus());
    if (bit.IsOne()) {
      arguments.push_back("1");
    } else if (bit.IsZero()) {
      arguments.push_back("0");
    } else {
      // We allow literals strictly for pulling values out of [param] arrays.
      for (const Node* user : literal->users()) {
        if (!user->Is<xls::ArrayIndex>()) {
          return absl::InvalidArgumentError("Unsupported literal value.");
        }
      }
      return "";
    }
  } else {
    for (const Node* operand_node : node->operands()) {
      arguments.push_back(NodeReference(operand_node));
    }
  }
  return absl::StrFormat(statement, NodeReference(node),
                         absl::StrJoin(arguments, ", "));
}

absl::StatusOr<std::string> TfheTranspiler::TranslateHeader(
    const xls::Function* function,
    const xlscc_metadata::MetadataOutput& metadata,
    absl::string_view header_path) {
  XLS_ASSIGN_OR_RETURN(const std::string header_guard,
                       PathToHeaderGuard(header_path));
  static constexpr absl::string_view kHeaderTemplate =
      R"(#ifndef $2
#define $2

// clang-format off
#include "$3"
// clang-format on
#include "absl/status/status.h"
#include "absl/types/span.h"
#include "tfhe/tfhe.h"
#include "tfhe/tfhe_io.h"
#include "transpiler/data/tfhe_data.h"

$0;

$1#endif  // $2
)";
  XLS_ASSIGN_OR_RETURN(std::string signature,
                       FunctionSignature(function, metadata));
  absl::optional<std::string> typed_overload =
      TypedOverload(metadata, "Tfhe", "absl::Span<LweSample>",
                    "const TFheGateBootstrappingCloudKeySet*");
  return absl::Substitute(kHeaderTemplate, signature,
                          typed_overload.value_or(""), header_guard,
                          GetTypeHeader(header_path));
}

absl::StatusOr<std::string> TfheTranspiler::FunctionSignature(
    const Function* function, const xlscc_metadata::MetadataOutput& metadata) {
  return transpiler::FunctionSignature(
      metadata, "LweSample", "const TFheGateBootstrappingCloudKeySet*", "bk");
}

absl::StatusOr<std::string> TfheTranspiler::Prelude(
    const Function* function, const xlscc_metadata::MetadataOutput& metadata) {
  // $0: function name
  // $1: non-key parameter string
  static constexpr absl::string_view kPrelude =
      R"(#include <unordered_map>

#include "absl/status/status.h"
#include "absl/types/span.h"
#include "tfhe/tfhe.h"
#include "tfhe/tfhe_io.h"

$0 {
  std::unordered_map<int, LweSample*> temp_nodes;

)";
  XLS_ASSIGN_OR_RETURN(std::string signature,
                       FunctionSignature(function, metadata));
  return absl::Substitute(kPrelude, signature);
}

absl::StatusOr<std::string> TfheTranspiler::Conclusion() {
  return R"(  for (auto pair : temp_nodes) {
    delete_gate_bootstrapping_ciphertext(pair.second);
  }
  return absl::OkStatus();
}
)";
}

}  // namespace transpiler
}  // namespace fully_homomorphic_encryption
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          lexer.cpp
* Purpose:       Implementation of lexer classes
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/stc/stc.h> // for wxSTC_KEYWORDSET_MAX
#include <wx/tokenzr.h>
#include <wx/extension/lexer.h>
#include <wx/extension/util.h> // for wxExGetWord

using namespace std;

const wxString wxExLexer::GetKeywordsString(int keyword_set) const
{
  wxString keywords;

  if (keyword_set == -1)
  {
    for (
      set<wxString>::const_iterator it = m_Keywords.begin();
      it != m_Keywords.end();
      ++it)
    {
      keywords += *it + " ";
    }
  }
  else
  {
    std::map< int, std::set<wxString> >::const_iterator it = m_KeywordsSet.find(keyword_set);

    if (it == m_KeywordsSet.end())
    {
      wxFAIL;
    }
    else
    {
      set<wxString> theset = it->second;

      for (
        set<wxString>::const_iterator it = theset.begin();
        it != theset.end();
        ++it)
      {
        keywords += *it + " ";
      }
    }
  }

  return keywords;
}

const wxString wxExLexer::GetFormattedText(
  const wxString& lines,
  const wxString& header,
  bool fill_out_with_space,
  bool fill_out) const
{
  wxString text = lines, header_to_use = header;
  size_t nCharIndex;

  wxString out;

  // Process text between the carriage return line feeds.
  while ((nCharIndex = text.find("\n")) != wxString::npos)
  {
    out << GetUnFormattedText(
      text.substr(0, nCharIndex),
      header_to_use,
      fill_out_with_space,
      fill_out);

    text = text.substr(nCharIndex + 1);
    header_to_use = wxString(' ', header.size());
  }

  if (!text.empty())
  {
    out << GetUnFormattedText(
      text,
      header_to_use,
      fill_out_with_space,
      fill_out);
  }

  return out;
}

const wxString wxExLexer::GetUnFormattedText(
  const wxString& lines,
  const wxString& header,
  bool fill_out_with_space,
  bool fill_out) const
{
  const size_t line_length = UsableCharactersPerLine();

  // Use the header, with one space extra to separate, or no header at all.
  const wxString header_with_spaces =
    (header.size() == 0) ? wxString(wxEmptyString) : wxString(' ', header.size());

  wxString in = lines, line = header;

  bool at_begin = true;
  wxString out;

  while (!in.empty())
  {
    const wxString word = wxExGetWord(in, false, false);

    if (line.size() + 1 + word.size() > line_length)
    {
      out << MakeSingleLineComment(line, fill_out_with_space, fill_out) << "\n";

      line = header_with_spaces + word;
    }
    else
    {
      line += (!line.empty() && !at_begin ? " ": wxString(wxEmptyString)) + word;
      at_begin = false;
    }
  }

  out << MakeSingleLineComment(line, fill_out_with_space, fill_out);

  return out;
}

bool wxExLexer::IsKeyword(const wxString& word) const
{
  set<wxString>::const_iterator it = m_Keywords.find(word);
  return (it != m_Keywords.end());
}

bool wxExLexer::KeywordStartsWith(const wxString& word) const
{
  for (
    set<wxString>::const_iterator it = m_Keywords.begin();
    it != m_Keywords.end();
    ++it)
  {
    if (it->Upper().StartsWith(word.Upper()))
    {
      return true;
    }
  }

  return false;
}

const wxString wxExLexer::MakeComment(
  const wxString& text,
  bool fill_out_with_space,
  bool fill_out) const
{
  wxString out;

  text.find("\n") != wxString::npos ?
    out << GetFormattedText(text, wxEmptyString, fill_out_with_space, fill_out):
    out << GetUnFormattedText(text, wxEmptyString, fill_out_with_space, fill_out);

  return out;
}

const wxString wxExLexer::MakeComment(
  const wxString& prefix,
  const wxString& text) const
{
  wxString out;

  text.find("\n") != wxString::npos ?
    out << GetFormattedText(text, prefix, true, true):
    out << GetUnFormattedText(text, prefix, true, true);

  return out;
}

const wxString wxExLexer::MakeSingleLineComment(
  const wxString& text,
  bool fill_out_with_space,
  bool fill_out) const
{
  if (m_CommentBegin.empty())
  {
    wxLogError(wxString::Format(
      _("No comments available for lexer: %s, cannot make comment"),
      m_ScintillaLexer.c_str());

    return wxEmptyString;
  }

  // First set the fill_out_character.
  wxChar fill_out_character;

  if (fill_out_with_space)
  {
    fill_out_character = ' ';
  }
  else
  {
    if (text.empty())
    {
      if (m_CommentBegin == m_CommentEnd || m_CommentEnd.empty())
           fill_out_character = '-';
      else fill_out_character = m_CommentBegin[m_CommentBegin.size() - 1];
    }
    else   fill_out_character = ' ';
  }

  wxString out = m_CommentBegin + fill_out_character + text;

  // Fill out characters.
  if (fill_out)
  {
    const int fill_chars = UsableCharactersPerLine() - text.size();

    if (fill_chars > 0)
    {
      const wxString fill_out(fill_out_character, fill_chars);
      out += fill_out;
    }
  }

  if (!m_CommentEnd.empty()) out += fill_out_character + m_CommentEnd;

  return out;
}

bool wxExLexer::SetKeywords(const wxString& value)
{
  set<wxString> keywords_set;

  wxStringTokenizer tkz(value, "\r\n ");

  int setno = 0;

  while (tkz.HasMoreTokens())
  {
    const wxString line = tkz.GetNextToken();
    wxStringTokenizer fields(line, ":");

    wxString keyword;

    if (fields.CountTokens() > 1)
    {
      keyword = fields.GetNextToken();

      const int new_setno = atoi(fields.GetNextToken().c_str());

      if (new_setno >= wxSTC_KEYWORDSET_MAX)
      {
        return false;
      }

      if (new_setno != setno)
      {
        if (!keywords_set.empty())
        {
          m_KeywordsSet.insert(make_pair(setno, keywords_set));
          keywords_set.clear();
        }

        setno = new_setno;
      }

      keywords_set.insert(keyword);
    }
    else
    {
      keyword = line;
      keywords_set.insert(line);
    }

    m_Keywords.insert(keyword);
  }

  m_KeywordsSet.insert(make_pair(setno, keywords_set));

  return true;
}

int wxExLexer::UsableCharactersPerLine() const
{
  // We always use lines with 80 characters. We adjust this here for
  // the space the beginning and end of the comment characters occupy.
  return 80
      -  (m_CommentBegin.size() + 1)
      - ((m_CommentEnd.size() != 0) ? m_CommentEnd.size() + 1 : 0);
}
<commit_msg>fixed error<commit_after>/******************************************************************************\
* File:          lexer.cpp
* Purpose:       Implementation of lexer classes
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/stc/stc.h> // for wxSTC_KEYWORDSET_MAX
#include <wx/tokenzr.h>
#include <wx/extension/lexer.h>
#include <wx/extension/util.h> // for wxExGetWord

using namespace std;

const wxString wxExLexer::GetKeywordsString(int keyword_set) const
{
  wxString keywords;

  if (keyword_set == -1)
  {
    for (
      set<wxString>::const_iterator it = m_Keywords.begin();
      it != m_Keywords.end();
      ++it)
    {
      keywords += *it + " ";
    }
  }
  else
  {
    std::map< int, std::set<wxString> >::const_iterator it = m_KeywordsSet.find(keyword_set);

    if (it == m_KeywordsSet.end())
    {
      wxFAIL;
    }
    else
    {
      set<wxString> theset = it->second;

      for (
        set<wxString>::const_iterator it = theset.begin();
        it != theset.end();
        ++it)
      {
        keywords += *it + " ";
      }
    }
  }

  return keywords;
}

const wxString wxExLexer::GetFormattedText(
  const wxString& lines,
  const wxString& header,
  bool fill_out_with_space,
  bool fill_out) const
{
  wxString text = lines, header_to_use = header;
  size_t nCharIndex;

  wxString out;

  // Process text between the carriage return line feeds.
  while ((nCharIndex = text.find("\n")) != wxString::npos)
  {
    out << GetUnFormattedText(
      text.substr(0, nCharIndex),
      header_to_use,
      fill_out_with_space,
      fill_out);

    text = text.substr(nCharIndex + 1);
    header_to_use = wxString(' ', header.size());
  }

  if (!text.empty())
  {
    out << GetUnFormattedText(
      text,
      header_to_use,
      fill_out_with_space,
      fill_out);
  }

  return out;
}

const wxString wxExLexer::GetUnFormattedText(
  const wxString& lines,
  const wxString& header,
  bool fill_out_with_space,
  bool fill_out) const
{
  const size_t line_length = UsableCharactersPerLine();

  // Use the header, with one space extra to separate, or no header at all.
  const wxString header_with_spaces =
    (header.size() == 0) ? wxString(wxEmptyString) : wxString(' ', header.size());

  wxString in = lines, line = header;

  bool at_begin = true;
  wxString out;

  while (!in.empty())
  {
    const wxString word = wxExGetWord(in, false, false);

    if (line.size() + 1 + word.size() > line_length)
    {
      out << MakeSingleLineComment(line, fill_out_with_space, fill_out) << "\n";

      line = header_with_spaces + word;
    }
    else
    {
      line += (!line.empty() && !at_begin ? " ": wxString(wxEmptyString)) + word;
      at_begin = false;
    }
  }

  out << MakeSingleLineComment(line, fill_out_with_space, fill_out);

  return out;
}

bool wxExLexer::IsKeyword(const wxString& word) const
{
  set<wxString>::const_iterator it = m_Keywords.find(word);
  return (it != m_Keywords.end());
}

bool wxExLexer::KeywordStartsWith(const wxString& word) const
{
  for (
    set<wxString>::const_iterator it = m_Keywords.begin();
    it != m_Keywords.end();
    ++it)
  {
    if (it->Upper().StartsWith(word.Upper()))
    {
      return true;
    }
  }

  return false;
}

const wxString wxExLexer::MakeComment(
  const wxString& text,
  bool fill_out_with_space,
  bool fill_out) const
{
  wxString out;

  text.find("\n") != wxString::npos ?
    out << GetFormattedText(text, wxEmptyString, fill_out_with_space, fill_out):
    out << GetUnFormattedText(text, wxEmptyString, fill_out_with_space, fill_out);

  return out;
}

const wxString wxExLexer::MakeComment(
  const wxString& prefix,
  const wxString& text) const
{
  wxString out;

  text.find("\n") != wxString::npos ?
    out << GetFormattedText(text, prefix, true, true):
    out << GetUnFormattedText(text, prefix, true, true);

  return out;
}

const wxString wxExLexer::MakeSingleLineComment(
  const wxString& text,
  bool fill_out_with_space,
  bool fill_out) const
{
  if (m_CommentBegin.empty())
  {
    wxLogError(wxString::Format(
      _("No comments available for lexer: %s, cannot make comment"),
      m_ScintillaLexer.c_str()));

    return wxEmptyString;
  }

  // First set the fill_out_character.
  wxChar fill_out_character;

  if (fill_out_with_space)
  {
    fill_out_character = ' ';
  }
  else
  {
    if (text.empty())
    {
      if (m_CommentBegin == m_CommentEnd || m_CommentEnd.empty())
           fill_out_character = '-';
      else fill_out_character = m_CommentBegin[m_CommentBegin.size() - 1];
    }
    else   fill_out_character = ' ';
  }

  wxString out = m_CommentBegin + fill_out_character + text;

  // Fill out characters.
  if (fill_out)
  {
    const int fill_chars = UsableCharactersPerLine() - text.size();

    if (fill_chars > 0)
    {
      const wxString fill_out(fill_out_character, fill_chars);
      out += fill_out;
    }
  }

  if (!m_CommentEnd.empty()) out += fill_out_character + m_CommentEnd;

  return out;
}

bool wxExLexer::SetKeywords(const wxString& value)
{
  set<wxString> keywords_set;

  wxStringTokenizer tkz(value, "\r\n ");

  int setno = 0;

  while (tkz.HasMoreTokens())
  {
    const wxString line = tkz.GetNextToken();
    wxStringTokenizer fields(line, ":");

    wxString keyword;

    if (fields.CountTokens() > 1)
    {
      keyword = fields.GetNextToken();

      const int new_setno = atoi(fields.GetNextToken().c_str());

      if (new_setno >= wxSTC_KEYWORDSET_MAX)
      {
        return false;
      }

      if (new_setno != setno)
      {
        if (!keywords_set.empty())
        {
          m_KeywordsSet.insert(make_pair(setno, keywords_set));
          keywords_set.clear();
        }

        setno = new_setno;
      }

      keywords_set.insert(keyword);
    }
    else
    {
      keyword = line;
      keywords_set.insert(line);
    }

    m_Keywords.insert(keyword);
  }

  m_KeywordsSet.insert(make_pair(setno, keywords_set));

  return true;
}

int wxExLexer::UsableCharactersPerLine() const
{
  // We always use lines with 80 characters. We adjust this here for
  // the space the beginning and end of the comment characters occupy.
  return 80
      -  (m_CommentBegin.size() + 1)
      - ((m_CommentEnd.size() != 0) ? m_CommentEnd.size() + 1 : 0);
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

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.
*/

#ifndef SRS_APP_DVR_HPP
#define SRS_APP_DVR_HPP

/*
#include <srs_app_dvr.hpp>
*/
#include <srs_core.hpp>

#ifdef SRS_AUTO_DVR

class SrsSource;
class SrsRequest;
class SrsAmf0Object;
class SrsSharedPtrMessage;

/**
* dvr(digital video recorder) to record RTMP stream to flv file.
* TODO: FIXME: add utest for it.
*/
class SrsDvr
{
private:
    SrsSource* _source;
public:
    SrsDvr(SrsSource* source);
    virtual ~SrsDvr();
public:
    /**
    * publish stream event, continue to write the m3u8,
    * for the muxer object not destroyed.
    */
    virtual int on_publish(SrsRequest* req);
    /**
    * the unpublish event, only close the muxer, donot destroy the
    * muxer, for when we continue to publish, the m3u8 will continue.
    */
    virtual void on_unpublish();
    /**
    * get some information from metadata, it's optinal.
    */
    virtual int on_meta_data(SrsAmf0Object* metadata);
    /**
    * mux the audio packets to ts.
    */
    virtual int on_audio(SrsSharedPtrMessage* audio);
    /**
    * mux the video packets to ts.
    */
    virtual int on_video(SrsSharedPtrMessage* video);
};

#endif

#endif<commit_msg>update dvr comments<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2014 winlin

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.
*/

#ifndef SRS_APP_DVR_HPP
#define SRS_APP_DVR_HPP

/*
#include <srs_app_dvr.hpp>
*/
#include <srs_core.hpp>

#ifdef SRS_AUTO_DVR

class SrsSource;
class SrsRequest;
class SrsAmf0Object;
class SrsSharedPtrMessage;

/**
* dvr(digital video recorder) to record RTMP stream to flv file.
* TODO: FIXME: add utest for it.
*/
class SrsDvr
{
private:
    SrsSource* _source;
public:
    SrsDvr(SrsSource* source);
    virtual ~SrsDvr();
public:
    /**
    * publish stream event,
    * when encoder start to publish RTMP stream.
    */
    virtual int on_publish(SrsRequest* req);
    /**
    * the unpublish event.,
    * when encoder stop(unpublish) to publish RTMP stream.
    */
    virtual void on_unpublish();
    /**
    * get some information from metadata, it's optinal.
    */
    virtual int on_meta_data(SrsAmf0Object* metadata);
    /**
    * mux the audio packets to dvr.
    */
    virtual int on_audio(SrsSharedPtrMessage* audio);
    /**
    * mux the video packets to dvr.
    */
    virtual int on_video(SrsSharedPtrMessage* video);
};

#endif

#endif<|endoftext|>


<commit_before>#include <glib/gstdio.h>

#include "imagelist.h"
using namespace AhoViewer;

#include "booru/image.h"
#include "naturalsort.h"
#include "settings.h"

ImageList::ImageList(Widget *const w)
  : m_Widget(w),
    m_Index(0),
    m_ThumbnailCancel(Gio::Cancellable::create()),
    m_ThumbnailThread(nullptr),
    m_CacheCancel(Gio::Cancellable::create()),
    m_CacheThread(nullptr)
{
    // Sorts indices based on how close they are to m_Index
    m_IndexSort = [ this ](size_t a, size_t b)
    {
        size_t adiff = std::abs(static_cast<int>(a - m_Index)),
               bdiff = std::abs(static_cast<int>(b - m_Index));
        return adiff == bdiff ? a > b : adiff < bdiff;
    };

    m_Widget->signal_selected_changed().connect(
            sigc::bind(sigc::mem_fun(*this, &ImageList::set_current), true, false));

    m_ThumbnailLoadedConn = m_SignalThumbnailLoaded.connect(sigc::mem_fun(*this, &ImageList::on_thumbnail_loaded));
    m_SignalThumbnailsLoaded.connect(sigc::mem_fun(*this, &ImageList::on_thumbnails_loaded));
}

ImageList::~ImageList()
{
    reset();
}

void ImageList::clear()
{
    reset();
    m_SignalCleared();
}

/**
 * Creates a local image list from a given file (archive/image) or direcotry.
 * The parameter index is used when reopening an archive at a given index.
 **/
bool ImageList::load(const std::string path, std::string &error, int index)
{
    std::unique_ptr<Archive> archive = nullptr;
    std::string dirPath;

    if (Glib::file_test(path, Glib::FILE_TEST_EXISTS))
    {
        if (Glib::file_test(path, Glib::FILE_TEST_IS_DIR))
        {
            dirPath = path;
        }
        else if (Image::is_valid(path))
        {
            dirPath = Glib::path_get_dirname(path);
        }
        else if ((archive = Archive::create(path)))
        {
            dirPath = archive->get_extracted_path();
        }
        else
        {
            error = "'" + Glib::path_get_basename(path) + "' is invalid or not supported.";
            return false;
        }
    }
    else
    {
        error = "File or directory '" + path + "' could not be opened.";
        return false;
    }

    std::vector<std::string> entries =
        archive ? archive->get_entries(Archive::IMAGES) : get_entries<Image>(dirPath);

    // No valid images in this directory
    if (entries.empty())
    {
        error = "No valid image files found in '" +
            Glib::path_get_basename(archive ? archive->get_path() : dirPath) + "'.";
        return false;
    }

    m_SignalLoadSuccess();
    reset();

    // Create the actual vector of images
    m_Images.reserve(entries.size());
    m_Widget->reserve(entries.size());

    if (archive)
    {
        m_Archive = std::move(archive);
        m_ArchiveEntries = get_entries<Archive>(Glib::path_get_dirname(m_Archive->get_path()));
        std::sort(m_ArchiveEntries.begin(), m_ArchiveEntries.end(), NaturalSort());
    }
    else
    {
        Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(dirPath);
        m_FileMonitor = dir->monitor_directory();
        m_FileMonitor->signal_changed().connect(sigc::mem_fun(*this, &ImageList::on_directory_changed));
    }

    std::sort(entries.begin(), entries.end(), NaturalSort());

    if (path != dirPath && !m_Archive)
    {
        std::vector<std::string>::iterator iter = std::find(entries.begin(), entries.end(), path);
        index = iter == entries.end() ? 0 : iter - entries.begin();
    }
    else if (index == -1)
    {
        index = entries.size() - 1;
    }

    for (const std::string &e : entries)
    {
        std::shared_ptr<Image> img;
        if (m_Archive)
            img = std::make_shared<Archive::Image>(e, *m_Archive);
        else
            img = std::make_shared<Image>(e);
        m_Images.push_back(std::move(img));
    }

    m_ThumbnailThread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &ImageList::load_thumbnails));
    set_current(index, false, true);

    return true;
}

void ImageList::go_next()
{
    set_current_relative(1);
}

void ImageList::go_previous()
{
    set_current_relative(-1);
}

void ImageList::go_first()
{
    set_current(0);
}

void ImageList::go_last()
{
    set_current(m_Images.size() - 1);
}

bool ImageList::can_go_next() const
{
    if (m_Index + 1 < m_Images.size())
        return true;
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
        return std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                m_Archive->get_path()) - m_ArchiveEntries.begin() < static_cast<long>(m_ArchiveEntries.size() - 1);

    return false;
}

bool ImageList::can_go_previous() const
{
    if (m_Index > 0)
        return true;
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
        return std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                m_Archive->get_path()) - m_ArchiveEntries.begin() > 0;

    return false;
}

void ImageList::on_cache_size_changed()
{
    if (!empty())
        update_cache();
}

void ImageList::set_current(const size_t index, const bool fromWidget, const bool force)
{
    if (index == m_Index && !force)
        return;

    m_Index = index;
    m_SignalChanged(m_Images[m_Index]);
    update_cache();

    if (!fromWidget)
        m_Widget->set_selected(m_Index);
}

void ImageList::load_thumbnails()
{
    Glib::ThreadPool pool(4);
    m_ThumbnailCancel->reset();

    std::vector<size_t> indices(m_Images.size());
    std::iota(indices.begin(), indices.end(), 0);
    std::sort(indices.begin(), indices.end(), m_IndexSort);

    for (const size_t i : indices)
    {
        pool.push([ this, i ]()
        {
            if (m_ThumbnailCancel->is_cancelled())
                return;

            const Glib::RefPtr<Gdk::Pixbuf> &thumb = m_Images[i]->get_thumbnail();
            {
                Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);
                m_ThumbnailQueue.push(PixbufPair(i, thumb));
            }

            if (!m_ThumbnailCancel->is_cancelled())
                m_SignalThumbnailLoaded();
        });
    }

    pool.shutdown(m_ThumbnailCancel->is_cancelled());

    if (!m_ThumbnailCancel->is_cancelled())
        m_SignalThumbnailsLoaded();
}

// Resets the image list to it's initial state
void ImageList::reset()
{
    cancel_cache();
    m_ThumbnailCancel->cancel();

    if (m_FileMonitor)
        m_FileMonitor->cancel();

    {
        Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);
        m_ThumbnailQueue = std::queue<PixbufPair>();
    }

    if (m_ThumbnailThread)
    {
        m_ThumbnailThread->join();
        m_ThumbnailThread = nullptr;
    }

    m_Images.clear();
    m_Widget->clear();

    m_Archive = nullptr;
    m_ArchiveEntries.clear();
    m_Index = 0;
}

/**
 * Returns an unsorted vector of the paths to valid T's.
 * T must have a static method ::is_valid, ie Image and Archive
 **/
template <typename T>
std::vector<std::string> ImageList::get_entries(const std::string &path)
{
    Glib::Dir dir(path);
    std::vector<std::string> entries(dir.begin(), dir.end());
    std::vector<std::string>::iterator i = entries.begin();

    while (i != entries.end())
    {
        // Make path absolute
        *i = Glib::build_filename(path, *i);

        // Make sure it is a loadable image/archive
        if (T::is_valid(*i))
            ++i;
        else
            i = entries.erase(i);
    }

    return entries;
}

void ImageList::on_thumbnail_loaded()
{
    m_ThumbnailLoadedConn.block();

    while (!m_ThumbnailQueue.empty() && !m_ThumbnailCancel->is_cancelled())
    {
        Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);

        PixbufPair p = m_ThumbnailQueue.front();
        m_Widget->set_pixbuf(p.first, p.second);
        m_ThumbnailQueue.pop();
    }

    m_ThumbnailLoadedConn.unblock();
}

void ImageList::on_thumbnails_loaded()
{
    m_ThumbnailThread->join();
    m_ThumbnailThread = nullptr;
}

void ImageList::on_directory_changed(const Glib::RefPtr<Gio::File> &file,
                                     const Glib::RefPtr<Gio::File>&,
                                     Gio::FileMonitorEvent event)
{
    if (!file) return;

    ImageVector::iterator it;
    auto comp = [ file ](const std::shared_ptr<Image> &i) { return i->get_path() == file->get_path(); };

    if (event == Gio::FILE_MONITOR_EVENT_DELETED)
    {
        if ((it = std::find_if(m_Images.begin(), m_Images.end(), comp)) != m_Images.end())
        {
            size_t index = it - m_Images.begin();
            bool current = index == m_Index;

            // Adjust m_Index if the deleted file was before it
            if (index < m_Index)
                --m_Index;

            m_Widget->erase(index);
            m_Images.erase(std::remove_if(m_Images.begin(), m_Images.end(), comp));

            if (current)
            {
                if (m_Images.empty())
                {
                    clear();
                    return;
                }
                else
                {
                    set_current(index == 0 ? 0 : index - 1, false, true);
                }
            }
            else
            {
                update_cache();
            }

            m_SignalSizeChanged();
        }
        else if (file->get_path() == Glib::path_get_dirname(get_current()->get_path()))
        {
            clear();
        }
    }
    // The changed event is used in case the created event was too quick,
    // and the file was invalid while still being written
    else if ((event == Gio::FILE_MONITOR_EVENT_CREATED ||
              event == Gio::FILE_MONITOR_EVENT_CHANGES_DONE_HINT) &&
            Image::is_valid(file->get_path()))
    {
        // Make sure the image wasn't already added
        if (event == Gio::FILE_MONITOR_EVENT_CHANGES_DONE_HINT &&
            std::find_if(m_Images.begin(), m_Images.end(), comp) != m_Images.end())
            return;

        std::shared_ptr<Image> img = std::make_shared<Image>(file->get_path());
        it = std::lower_bound(m_Images.begin(), m_Images.end(), img, NaturalSort());
        size_t index = it - m_Images.begin();

        if (index <= m_Index)
            ++m_Index;

        m_Widget->insert(index, img->get_thumbnail());
        m_Images.insert(it, img);

        update_cache();
        m_SignalSizeChanged();
    }
}

void ImageList::set_current_relative(const int d)
{
    if ((d > 0 && m_Index + 1 < m_Images.size()) || (d < 0 && m_Index > 0))
    {
        set_current(m_Index + d);
    }
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
    {
        size_t i = std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                        m_Archive->get_path()) - m_ArchiveEntries.begin();

        if ((d > 0 && i < m_ArchiveEntries.size() - 1) || (d < 0 && i > 0))
        {
            std::string e;
            if (!load(m_ArchiveEntries[i + d], e, d < 0 ? -1 : 0))
                m_SignalArchiveError(e);
        }
    }
}

void ImageList::update_cache()
{
    std::vector<size_t> cache(m_Images.size()), diff;
    std::iota(cache.begin(), cache.end(), 0);
    std::sort(cache.begin(), cache.end(), m_IndexSort);

    cache.resize(Settings.get_int("CacheSize") * 2 + 1);

    // Get the indices of the images no longer in the cache
    if (!m_Cache.empty())
    {
        std::sort(m_Cache.begin(), m_Cache.end());
        std::sort(cache.begin(), cache.end());
        std::set_difference(m_Cache.begin(), m_Cache.end(),
                cache.begin(), cache.end(), std::back_inserter(diff));
    }

    cancel_cache();

    for (const size_t i : diff)
        if (i < m_Images.size() - 1)
            m_Images[i]->reset_pixbuf();

    // Start the cache loading thread
    m_Cache = cache;
    m_CacheThread = Glib::Threads::Thread::create([ this ]()
    {
        for (const size_t i : m_Cache)
        {
            if (m_CacheCancel->is_cancelled())
                break;

            m_Images[i]->load_pixbuf();
        }
    });
}

void ImageList::cancel_cache()
{
    if (m_CacheThread)
    {
        m_CacheCancel->cancel();

        m_CacheThread->join();
        m_CacheThread = nullptr;
        m_CacheCancel->reset();

        m_Cache.clear();
    }
}
<commit_msg>imagelist: Use iter from from instead of calling remove<commit_after>#include <glib/gstdio.h>

#include "imagelist.h"
using namespace AhoViewer;

#include "booru/image.h"
#include "naturalsort.h"
#include "settings.h"

ImageList::ImageList(Widget *const w)
  : m_Widget(w),
    m_Index(0),
    m_ThumbnailCancel(Gio::Cancellable::create()),
    m_ThumbnailThread(nullptr),
    m_CacheCancel(Gio::Cancellable::create()),
    m_CacheThread(nullptr)
{
    // Sorts indices based on how close they are to m_Index
    m_IndexSort = [ this ](size_t a, size_t b)
    {
        size_t adiff = std::abs(static_cast<int>(a - m_Index)),
               bdiff = std::abs(static_cast<int>(b - m_Index));
        return adiff == bdiff ? a > b : adiff < bdiff;
    };

    m_Widget->signal_selected_changed().connect(
            sigc::bind(sigc::mem_fun(*this, &ImageList::set_current), true, false));

    m_ThumbnailLoadedConn = m_SignalThumbnailLoaded.connect(sigc::mem_fun(*this, &ImageList::on_thumbnail_loaded));
    m_SignalThumbnailsLoaded.connect(sigc::mem_fun(*this, &ImageList::on_thumbnails_loaded));
}

ImageList::~ImageList()
{
    reset();
}

void ImageList::clear()
{
    reset();
    m_SignalCleared();
}

/**
 * Creates a local image list from a given file (archive/image) or direcotry.
 * The parameter index is used when reopening an archive at a given index.
 **/
bool ImageList::load(const std::string path, std::string &error, int index)
{
    std::unique_ptr<Archive> archive = nullptr;
    std::string dirPath;

    if (Glib::file_test(path, Glib::FILE_TEST_EXISTS))
    {
        if (Glib::file_test(path, Glib::FILE_TEST_IS_DIR))
        {
            dirPath = path;
        }
        else if (Image::is_valid(path))
        {
            dirPath = Glib::path_get_dirname(path);
        }
        else if ((archive = Archive::create(path)))
        {
            dirPath = archive->get_extracted_path();
        }
        else
        {
            error = "'" + Glib::path_get_basename(path) + "' is invalid or not supported.";
            return false;
        }
    }
    else
    {
        error = "File or directory '" + path + "' could not be opened.";
        return false;
    }

    std::vector<std::string> entries =
        archive ? archive->get_entries(Archive::IMAGES) : get_entries<Image>(dirPath);

    // No valid images in this directory
    if (entries.empty())
    {
        error = "No valid image files found in '" +
            Glib::path_get_basename(archive ? archive->get_path() : dirPath) + "'.";
        return false;
    }

    m_SignalLoadSuccess();
    reset();

    // Create the actual vector of images
    m_Images.reserve(entries.size());
    m_Widget->reserve(entries.size());

    if (archive)
    {
        m_Archive = std::move(archive);
        m_ArchiveEntries = get_entries<Archive>(Glib::path_get_dirname(m_Archive->get_path()));
        std::sort(m_ArchiveEntries.begin(), m_ArchiveEntries.end(), NaturalSort());
    }
    else
    {
        Glib::RefPtr<Gio::File> dir = Gio::File::create_for_path(dirPath);
        m_FileMonitor = dir->monitor_directory();
        m_FileMonitor->signal_changed().connect(sigc::mem_fun(*this, &ImageList::on_directory_changed));
    }

    std::sort(entries.begin(), entries.end(), NaturalSort());

    if (path != dirPath && !m_Archive)
    {
        std::vector<std::string>::iterator iter = std::find(entries.begin(), entries.end(), path);
        index = iter == entries.end() ? 0 : iter - entries.begin();
    }
    else if (index == -1)
    {
        index = entries.size() - 1;
    }

    for (const std::string &e : entries)
    {
        std::shared_ptr<Image> img;
        if (m_Archive)
            img = std::make_shared<Archive::Image>(e, *m_Archive);
        else
            img = std::make_shared<Image>(e);
        m_Images.push_back(std::move(img));
    }

    m_ThumbnailThread = Glib::Threads::Thread::create(sigc::mem_fun(*this, &ImageList::load_thumbnails));
    set_current(index, false, true);

    return true;
}

void ImageList::go_next()
{
    set_current_relative(1);
}

void ImageList::go_previous()
{
    set_current_relative(-1);
}

void ImageList::go_first()
{
    set_current(0);
}

void ImageList::go_last()
{
    set_current(m_Images.size() - 1);
}

bool ImageList::can_go_next() const
{
    if (m_Index + 1 < m_Images.size())
        return true;
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
        return std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                m_Archive->get_path()) - m_ArchiveEntries.begin() < static_cast<long>(m_ArchiveEntries.size() - 1);

    return false;
}

bool ImageList::can_go_previous() const
{
    if (m_Index > 0)
        return true;
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
        return std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                m_Archive->get_path()) - m_ArchiveEntries.begin() > 0;

    return false;
}

void ImageList::on_cache_size_changed()
{
    if (!empty())
        update_cache();
}

void ImageList::set_current(const size_t index, const bool fromWidget, const bool force)
{
    if (index == m_Index && !force)
        return;

    m_Index = index;
    m_SignalChanged(m_Images[m_Index]);
    update_cache();

    if (!fromWidget)
        m_Widget->set_selected(m_Index);
}

void ImageList::load_thumbnails()
{
    Glib::ThreadPool pool(4);
    m_ThumbnailCancel->reset();

    std::vector<size_t> indices(m_Images.size());
    std::iota(indices.begin(), indices.end(), 0);
    std::sort(indices.begin(), indices.end(), m_IndexSort);

    for (const size_t i : indices)
    {
        pool.push([ this, i ]()
        {
            if (m_ThumbnailCancel->is_cancelled())
                return;

            const Glib::RefPtr<Gdk::Pixbuf> &thumb = m_Images[i]->get_thumbnail();
            {
                Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);
                m_ThumbnailQueue.push(PixbufPair(i, thumb));
            }

            if (!m_ThumbnailCancel->is_cancelled())
                m_SignalThumbnailLoaded();
        });
    }

    pool.shutdown(m_ThumbnailCancel->is_cancelled());

    if (!m_ThumbnailCancel->is_cancelled())
        m_SignalThumbnailsLoaded();
}

// Resets the image list to it's initial state
void ImageList::reset()
{
    cancel_cache();
    m_ThumbnailCancel->cancel();

    if (m_FileMonitor)
        m_FileMonitor->cancel();

    {
        Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);
        m_ThumbnailQueue = std::queue<PixbufPair>();
    }

    if (m_ThumbnailThread)
    {
        m_ThumbnailThread->join();
        m_ThumbnailThread = nullptr;
    }

    m_Images.clear();
    m_Widget->clear();

    m_Archive = nullptr;
    m_ArchiveEntries.clear();
    m_Index = 0;
}

/**
 * Returns an unsorted vector of the paths to valid T's.
 * T must have a static method ::is_valid, ie Image and Archive
 **/
template <typename T>
std::vector<std::string> ImageList::get_entries(const std::string &path)
{
    Glib::Dir dir(path);
    std::vector<std::string> entries(dir.begin(), dir.end());
    std::vector<std::string>::iterator i = entries.begin();

    while (i != entries.end())
    {
        // Make path absolute
        *i = Glib::build_filename(path, *i);

        // Make sure it is a loadable image/archive
        if (T::is_valid(*i))
            ++i;
        else
            i = entries.erase(i);
    }

    return entries;
}

void ImageList::on_thumbnail_loaded()
{
    m_ThumbnailLoadedConn.block();

    while (!m_ThumbnailQueue.empty() && !m_ThumbnailCancel->is_cancelled())
    {
        Glib::Threads::Mutex::Lock lock(m_ThumbnailMutex);

        PixbufPair p = m_ThumbnailQueue.front();
        m_Widget->set_pixbuf(p.first, p.second);
        m_ThumbnailQueue.pop();
    }

    m_ThumbnailLoadedConn.unblock();
}

void ImageList::on_thumbnails_loaded()
{
    m_ThumbnailThread->join();
    m_ThumbnailThread = nullptr;
}

void ImageList::on_directory_changed(const Glib::RefPtr<Gio::File> &file,
                                     const Glib::RefPtr<Gio::File>&,
                                     Gio::FileMonitorEvent event)
{
    if (!file) return;

    ImageVector::iterator it;
    auto comp = [ file ](const std::shared_ptr<Image> &i) { return i->get_path() == file->get_path(); };

    if (event == Gio::FILE_MONITOR_EVENT_DELETED)
    {
        if ((it = std::find_if(m_Images.begin(), m_Images.end(), comp)) != m_Images.end())
        {
            size_t index = it - m_Images.begin();
            bool current = index == m_Index;

            // Adjust m_Index if the deleted file was before it
            if (index < m_Index)
                --m_Index;

            m_Widget->erase(index);
            m_Images.erase(it);

            if (current)
            {
                if (m_Images.empty())
                {
                    clear();
                    return;
                }
                else
                {
                    set_current(index == 0 ? 0 : index - 1, false, true);
                }
            }
            else
            {
                update_cache();
            }

            m_SignalSizeChanged();
        }
        else if (file->get_path() == Glib::path_get_dirname(get_current()->get_path()))
        {
            clear();
        }
    }
    // The changed event is used in case the created event was too quick,
    // and the file was invalid while still being written
    else if ((event == Gio::FILE_MONITOR_EVENT_CREATED ||
              event == Gio::FILE_MONITOR_EVENT_CHANGES_DONE_HINT) &&
            Image::is_valid(file->get_path()))
    {
        // Make sure the image wasn't already added
        if (event == Gio::FILE_MONITOR_EVENT_CHANGES_DONE_HINT &&
            std::find_if(m_Images.begin(), m_Images.end(), comp) != m_Images.end())
            return;

        std::shared_ptr<Image> img = std::make_shared<Image>(file->get_path());
        it = std::lower_bound(m_Images.begin(), m_Images.end(), img, NaturalSort());
        size_t index = it - m_Images.begin();

        if (index <= m_Index)
            ++m_Index;

        m_Widget->insert(index, img->get_thumbnail());
        m_Images.insert(it, img);

        update_cache();
        m_SignalSizeChanged();
    }
}

void ImageList::set_current_relative(const int d)
{
    if ((d > 0 && m_Index + 1 < m_Images.size()) || (d < 0 && m_Index > 0))
    {
        set_current(m_Index + d);
    }
    else if (m_Archive && Settings.get_bool("AutoOpenArchive"))
    {
        size_t i = std::find(m_ArchiveEntries.begin(), m_ArchiveEntries.end(),
                        m_Archive->get_path()) - m_ArchiveEntries.begin();

        if ((d > 0 && i < m_ArchiveEntries.size() - 1) || (d < 0 && i > 0))
        {
            std::string e;
            if (!load(m_ArchiveEntries[i + d], e, d < 0 ? -1 : 0))
                m_SignalArchiveError(e);
        }
    }
}

void ImageList::update_cache()
{
    std::vector<size_t> cache(m_Images.size()), diff;
    std::iota(cache.begin(), cache.end(), 0);
    std::sort(cache.begin(), cache.end(), m_IndexSort);

    cache.resize(Settings.get_int("CacheSize") * 2 + 1);

    // Get the indices of the images no longer in the cache
    if (!m_Cache.empty())
    {
        std::sort(m_Cache.begin(), m_Cache.end());
        std::sort(cache.begin(), cache.end());
        std::set_difference(m_Cache.begin(), m_Cache.end(),
                cache.begin(), cache.end(), std::back_inserter(diff));
    }

    cancel_cache();

    for (const size_t i : diff)
        if (i < m_Images.size() - 1)
            m_Images[i]->reset_pixbuf();

    // Start the cache loading thread
    m_Cache = cache;
    m_CacheThread = Glib::Threads::Thread::create([ this ]()
    {
        for (const size_t i : m_Cache)
        {
            if (m_CacheCancel->is_cancelled())
                break;

            m_Images[i]->load_pixbuf();
        }
    });
}

void ImageList::cancel_cache()
{
    if (m_CacheThread)
    {
        m_CacheCancel->cancel();

        m_CacheThread->join();
        m_CacheThread = nullptr;
        m_CacheCancel->reset();

        m_Cache.clear();
    }
}
<|endoftext|>


<commit_before>//  This tutorial demonstrates:
//  - how to directly access and manipulate ARGB pixel values of an image.
//  - how to make a part of an image to be transparent.
//  - how to merge/alphablend an image with transparent colors
//    with some background image.
//Author: Valeriy Onuchin

#include "TColor.h"
#include "TImage.h"
#include "TImageDump.h"
#include "TVirtualPad.h"
#include "TROOT.h"
#include "TFrame.h"

static UInt_t color2rgb(TColor *col)
{
   // returns RGB value of color

   return ((UInt_t(col->GetRed()*255) << 16) +
           (UInt_t(col->GetGreen()*255) << 8) +
            UInt_t(col->GetBlue()*255));
}

void trans_graph()
{
   gROOT->SetBatch();

   // execute graph.C macro
   gROOT->Macro("$ROOTSYS/tutorials/graphs/graph.C");

   // create gVirtualPS object
   TImageDump dmp("dummy.png");
   TImage *fore = dmp.GetImage();  // image associated with image_dump

   // resize canvas
   gPad->SetCanvasSize(400, 300);
   gPad->Paint(); // paint gPad on fore image associated with TImageDump

   // open background image
   TImage *back = TImage::Open("$ROOTSYS/tutorials/image/rose512.jpg");

   // choose colors to be transparent
   TColor *bk1 = gROOT->GetColor(gPad->GetFillColor());
   TColor *bk2 = gROOT->GetColor(gPad->GetFrame()->GetFillColor());
   UInt_t rgb1 = color2rgb(bk1);
   UInt_t rgb2 = color2rgb(bk2);

   // get directly accessible ARGB array
   UInt_t *argb = fore->GetArgbArray();
   UInt_t w = fore->GetWidth();
   UInt_t h = fore->GetHeight();

   // scan all pixels in fore image and
   // make rgb1, rgb2 colors transparent.
   for (UInt_t i = 0; i < h; i++) {
      for (UInt_t j = 0; j < w; j++) {
         Int_t idx = i*w + j;

         // RGB part of ARGB color
         UInt_t col = argb[idx] & 0xffffff;

         // 24..31 bits define transparency of the color in the range 0 - 0xff
         // for example, 0x00000000 - black color with 100% transparency
         //              0xff000000 - non-transparent black color

         if ((col == rgb1) || (col == rgb2)) { //
            argb[idx] = 0; // 100% transparent
         } else {
            argb[idx] = 0xff000000 + col;  // make other pixels non-transparent
         }
      }
   }

   // alphablend back and fore images
   back->Merge(fore, "alphablend", 20, 20);

   // write result image in PNG format
   back->WriteImage("trans_graph.png");
   printf("*************** File trans_graph.png created ***************\n");

   delete back;
}
<commit_msg>- From V.Onuchin:   Mods which allow to run this script by clicking with a ROOT browser,   i.e. in gui mode (add switching back to GUI mode at the end of script).<commit_after>//  This tutorial demonstrates:
//  - how to directly access and manipulate ARGB pixel values of an image.
//  - how to make a part of an image to be transparent.
//  - how to merge/alphablend an image with transparent colors
//    with some background image.
//Author: Valeriy Onuchin

#include "TColor.h"
#include "TImage.h"
#include "TImageDump.h"
#include "TVirtualPad.h"
#include "TROOT.h"
#include "TFrame.h"

static UInt_t color2rgb(TColor *col)
{
   // returns RGB value of color

   return ((UInt_t(col->GetRed()*255) << 16) +
           (UInt_t(col->GetGreen()*255) << 8) +
            UInt_t(col->GetBlue()*255));
}

void trans_graph()
{
   // remember if  we are in batch mode
   Bool_t batch = gROOT->IsBatch();

   // switch to batch mode
   gROOT->SetBatch(kTRUE);

   // execute graph.C macro
   gROOT->Macro("$ROOTSYS/tutorials/graphs/graph.C");

   // create gVirtualPS object
   TImageDump dmp("dummy.png");
   TImage *fore = dmp.GetImage();  // image associated with image_dump

   // resize canvas
   gPad->SetCanvasSize(400, 300);
   gPad->Paint(); // paint gPad on fore image associated with TImageDump

   // open background image
   TImage *back = TImage::Open("$ROOTSYS/tutorials/image/rose512.jpg");

   // choose colors to be transparent
   TColor *bk1 = gROOT->GetColor(gPad->GetFillColor());
   TColor *bk2 = gROOT->GetColor(gPad->GetFrame()->GetFillColor());
   UInt_t rgb1 = color2rgb(bk1);
   UInt_t rgb2 = color2rgb(bk2);

   // get directly accessible ARGB array
   UInt_t *argb = fore->GetArgbArray();
   UInt_t w = fore->GetWidth();
   UInt_t h = fore->GetHeight();

   // scan all pixels in fore image and
   // make rgb1, rgb2 colors transparent.
   for (UInt_t i = 0; i < h; i++) {
      for (UInt_t j = 0; j < w; j++) {
         Int_t idx = i*w + j;

         // RGB part of ARGB color
         UInt_t col = argb[idx] & 0xffffff;

         // 24..31 bits define transparency of the color in the range 0 - 0xff
         // for example, 0x00000000 - black color with 100% transparency
         //              0xff000000 - non-transparent black color

         if ((col == rgb1) || (col == rgb2)) { //
            argb[idx] = 0; // 100% transparent
         } else {
            argb[idx] = 0xff000000 + col;  // make other pixels non-transparent
         }
      }
   }

   // alphablend back and fore images
   back->Merge(fore, "alphablend", 20, 20);

   // write result image in PNG format
   back->WriteImage("trans_graph.png");
   printf("*************** File trans_graph.png created ***************\n");

   delete back;

   // switch back to GUI mode
   if (!batch) gROOT->SetBatch(kFALSE);
}
<|endoftext|>


<commit_before>#include <ros/ros.h>

#include <geometry_msgs/Twist.h>

#include <tf/transform_broadcaster.h>

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>

#include <sys/time.h>

#include "imu/bool_msg.h"
#include "Comm.h"

#include <sensor_msgs/Imu.h>

#include <stdexcept>

class CheckSumError : public std::logic_error {
public:
    CheckSumError(const std::string &data) :
        std::logic_error("Received the Invalid IMU Data: " + data)
    {
    }
};

float deg_to_rad(float deg) {
    return deg / 180.0f * M_PI;
}

template<class T>
bool isInRange(T value, T max, T min){
    return (value >= min) && (value <= max);
}

struct ImuData {
    double angular_deg[3];
		bool flag;

    ImuData(){
        for(int i=0; i < 2; i++){
            angular_deg[i] = 0;
        }
    }
};

// 角度ごとにURGのデータを送信するためのサービス
// 要求があったときに，URGのデータを別のトピックに送信するだけ
class IMU {
private:
    ros::Publisher imu_pub_;
    ros::ServiceServer reset_service_;
    ros::ServiceServer carivrate_service_;
    float geta;
    CComm* usb;
    double gyro_unit;
    double acc_unit;
    double init_angle;
    std::string port_name;
    int   baudrate;
    ros::Rate loop_rate;
    int  z_axis_dir_;

    ImuData getImuData(){
        ImuData data;
        char command[2] = {0};
        char command2[50] = {0};
        char temp[6];
        unsigned long int sum = 0;

        const float temp_unit = 0.00565;

        sprintf(command, "o");
        usb->Send(command, strlen(command));
        ros::Duration(0.03).sleep();

        usb->Recv(command2, 50);
        ROS_INFO_STREAM("recv = " << command2);

        if (command2[0] == '\0') {
        	data.flag = false;
        	return data;
        }
        data.flag = true;

        memmove(temp,command2,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[0] = ((short)strtol(temp, NULL, 16)) * gyro_unit;
        memmove(temp,command2+4,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[1] = ((short)strtol(temp, NULL, 16)) * gyro_unit;
        memmove(temp,command2+8,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[2] = ((short)strtol(temp, NULL, 16)) * gyro_unit * z_axis_dir_;

        memmove(temp,command2+12,4);

        if(sum != ((short)strtol(temp, NULL, 16))){
            ROS_ERROR_STREAM("Recv Checksum: " << ((short)strtol(temp, NULL, 16)));
            ROS_ERROR_STREAM("Calculate Checksum: " << sum);
            throw CheckSumError(command2);
        }
        //while(data.angular_deg[2] < -180) data.angular_deg[2] += 180;
        //while(data.angular_deg[2] > 180) data.angular_deg[2] -= 180;

        return data;
    }

public:
    bool resetCallback(imu::bool_msg::Request  &req,
            imu::bool_msg::Response &res)
    {
        char command[2] = {0};
        sprintf(command, "0");
        usb->Send(command, strlen(command));
        sleep(1);
        std::cout << "Gyro 0 Reset" << std::endl;
        return true;
    }

    bool caribrateCallback(imu::bool_msg::Request  &req,
            imu::bool_msg::Response &res)
    {
        char command[2] = {0};
        std::cout << "Calibration" << std::endl;
        sprintf(command, "a");
        usb->Send(command, strlen(command));
        std::cout << "Caribrate start ";
        for(int i=0; i<8; ++i) {
            std::cout << ". ";
            sleep(1);
        }
        std::cout << "finish." << std::endl;
        return true;
    }

    IMU(ros::NodeHandle node) :
        imu_pub_(node.advertise<sensor_msgs::Imu>("imu", 10)),
        reset_service_(node.advertiseService("imu_reset", &IMU::resetCallback, this)),
        carivrate_service_(node.advertiseService("imu_caribrate", &IMU::caribrateCallback, this)),
        geta(0), gyro_unit(0.00836181640625), acc_unit(0.8), init_angle(0.0),
        port_name("/dev/ttyUSB0"), baudrate(115200), loop_rate(50), z_axis_dir_(-1)
    {
        ros::NodeHandle private_nh("~");
        private_nh.getParam("port_name", port_name);
        private_nh.param<double>("gyro_unit", gyro_unit, gyro_unit);
        private_nh.param<double>("acc_unit", acc_unit, acc_unit);
        private_nh.param<int>("baud_rate", baudrate, baudrate);
        private_nh.param<double>("init_angle", init_angle, init_angle);
        private_nh.param<int>("z_axis_dir", z_axis_dir_, z_axis_dir_);
				usb = new CComm(port_name, baudrate);
    }

    bool init() {
        char command[2] = {0};
        char command2[101] = {0};
        //シリアルポートオープン
        if (!usb->Open()) {
            std::cerr << "open error" << std::endl;
            return false;
        }
        std::cout << "device open success" << std::endl;
        sleep(1);
        //コンフィギュレーション キャリブレーション
        // if(m_calibration == true){
        std::cout << "Calibration" << std::endl;
        sprintf(command, "a");
        usb->Send(command, strlen(command));
        std::cout << "send = " << command << std::endl;
        for(int i=0; i<8; ++i) {
            printf(". ");
            sleep(1);
        }
        // }
        //コンフィギュレーション リセット
        // if(m_reset == true){
        sprintf(command, "0");
        usb->Send(command, strlen(command));        //送信
        std::cout << "send = " << command << std::endl;
        sleep(1);
        std::cout << "Gyro 0 Reset" << std::endl;
        // }
        geta = 0;
        usb->Recv(command2, 100);        //空読み バッファクリアが効かない？
        usb->ClearRecvBuf();                //バッファクリア
        return true;
    }

    void run() {
        double old_angular_z_deg = getImuData().angular_deg[2];
        double angular_z_deg = 0;
        unsigned short abnormal_count = 0;

        while (ros::ok()) {
            tf::Quaternion q;
            sensor_msgs::Imu output_msg;
            try{
                ImuData data = getImuData();
                if (data.flag == false){
                    usb->Close();
                    if(!usb->Open()) {
                        std::cerr << "reconnecting" << std::endl;
                    }
                }else{
                    output_msg.header.stamp = ros::Time::now();

                    ROS_INFO_STREAM("x_deg = " << data.angular_deg[0]);
                    ROS_INFO_STREAM("y_deg = " << data.angular_deg[1]);
                    ROS_INFO_STREAM("z_deg = " << data.angular_deg[2]);

                    if(!isInRange(std::abs(old_angular_z_deg), 180.0, 165.0) && !isInRange(std::abs(data.angular_deg[2]), 180.0, 165.0) &&
                        std::abs(old_angular_z_deg - data.angular_deg[2]) > 40 && abnormal_count < 4){

                        ROS_WARN_STREAM("Angle change too large: z = " << data.angular_deg[2]);
                        ROS_WARN_STREAM("old_z = " << old_angular_z_deg);
                        abnormal_count++;
                        continue;
                    }else{
                        abnormal_count = 0;
                        angular_z_deg = data.angular_deg[2];
                    }

                    q = tf::createQuaternionFromRPY(deg_to_rad(data.angular_deg[0]), deg_to_rad(-data.angular_deg[1]), deg_to_rad(angular_z_deg));
                    tf::quaternionTFToMsg(q, output_msg.orientation);
                    imu_pub_.publish(output_msg);
                    old_angular_z_deg = angular_z_deg;

                }
            }catch(const CheckSumError &e){
                output_msg.header.stamp = ros::Time::now();
                ROS_ERROR_STREAM(e.what());
                continue;
            }

            ros::spinOnce();
            //loop_rate.sleep();
        }
    }
};

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "imu");
    ros::NodeHandle node;
    IMU imu(node);
    if(!imu.init()) return 1;
    imu.run();

    return 0;
}
<commit_msg>fix the default node name<commit_after>#include <ros/ros.h>

#include <geometry_msgs/Twist.h>

#include <tf/transform_broadcaster.h>

#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>

#include <sys/time.h>

#include "imu/bool_msg.h"
#include "Comm.h"

#include <sensor_msgs/Imu.h>

#include <stdexcept>

class CheckSumError : public std::logic_error {
public:
    CheckSumError(const std::string &data) :
        std::logic_error("Received the Invalid IMU Data: " + data)
    {
    }
};

float deg_to_rad(float deg) {
    return deg / 180.0f * M_PI;
}

template<class T>
bool isInRange(T value, T max, T min){
    return (value >= min) && (value <= max);
}

struct ImuData {
    double angular_deg[3];
		bool flag;

    ImuData(){
        for(int i=0; i < 2; i++){
            angular_deg[i] = 0;
        }
    }
};

// 角度ごとにURGのデータを送信するためのサービス
// 要求があったときに，URGのデータを別のトピックに送信するだけ
class IMU {
private:
    ros::Publisher imu_pub_;
    ros::ServiceServer reset_service_;
    ros::ServiceServer carivrate_service_;
    float geta;
    CComm* usb;
    double gyro_unit;
    double acc_unit;
    double init_angle;
    std::string port_name;
    int   baudrate;
    ros::Rate loop_rate;
    int  z_axis_dir_;

    ImuData getImuData(){
        ImuData data;
        char command[2] = {0};
        char command2[50] = {0};
        char temp[6];
        unsigned long int sum = 0;

        const float temp_unit = 0.00565;

        sprintf(command, "o");
        usb->Send(command, strlen(command));
        ros::Duration(0.03).sleep();

        usb->Recv(command2, 50);
        ROS_INFO_STREAM("recv = " << command2);

        if (command2[0] == '\0') {
        	data.flag = false;
        	return data;
        }
        data.flag = true;

        memmove(temp,command2,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[0] = ((short)strtol(temp, NULL, 16)) * gyro_unit;
        memmove(temp,command2+4,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[1] = ((short)strtol(temp, NULL, 16)) * gyro_unit;
        memmove(temp,command2+8,4);
        sum = sum ^ ((short)strtol(temp, NULL, 16));
        data.angular_deg[2] = ((short)strtol(temp, NULL, 16)) * gyro_unit * z_axis_dir_;

        memmove(temp,command2+12,4);

        if(sum != ((short)strtol(temp, NULL, 16))){
            ROS_ERROR_STREAM("Recv Checksum: " << ((short)strtol(temp, NULL, 16)));
            ROS_ERROR_STREAM("Calculate Checksum: " << sum);
            throw CheckSumError(command2);
        }
        //while(data.angular_deg[2] < -180) data.angular_deg[2] += 180;
        //while(data.angular_deg[2] > 180) data.angular_deg[2] -= 180;

        return data;
    }

public:
    bool resetCallback(imu::bool_msg::Request  &req,
            imu::bool_msg::Response &res)
    {
        char command[2] = {0};
        sprintf(command, "0");
        usb->Send(command, strlen(command));
        sleep(1);
        std::cout << "Gyro 0 Reset" << std::endl;
        return true;
    }

    bool caribrateCallback(imu::bool_msg::Request  &req,
            imu::bool_msg::Response &res)
    {
        char command[2] = {0};
        std::cout << "Calibration" << std::endl;
        sprintf(command, "a");
        usb->Send(command, strlen(command));
        std::cout << "Caribrate start ";
        for(int i=0; i<8; ++i) {
            std::cout << ". ";
            sleep(1);
        }
        std::cout << "finish." << std::endl;
        return true;
    }

    IMU(ros::NodeHandle node) :
        imu_pub_(node.advertise<sensor_msgs::Imu>("imu", 10)),
        reset_service_(node.advertiseService("imu_reset", &IMU::resetCallback, this)),
        carivrate_service_(node.advertiseService("imu_caribrate", &IMU::caribrateCallback, this)),
        geta(0), gyro_unit(0.00836181640625), acc_unit(0.8), init_angle(0.0),
        port_name("/dev/ttyUSB0"), baudrate(115200), loop_rate(50), z_axis_dir_(-1)
    {
        ros::NodeHandle private_nh("~");
        private_nh.getParam("port_name", port_name);
        private_nh.param<double>("gyro_unit", gyro_unit, gyro_unit);
        private_nh.param<double>("acc_unit", acc_unit, acc_unit);
        private_nh.param<int>("baud_rate", baudrate, baudrate);
        private_nh.param<double>("init_angle", init_angle, init_angle);
        private_nh.param<int>("z_axis_dir", z_axis_dir_, z_axis_dir_);
				usb = new CComm(port_name, baudrate);
    }

    bool init() {
        char command[2] = {0};
        char command2[101] = {0};
        //シリアルポートオープン
        if (!usb->Open()) {
            std::cerr << "open error" << std::endl;
            return false;
        }
        std::cout << "device open success" << std::endl;
        sleep(1);
        //コンフィギュレーション キャリブレーション
        // if(m_calibration == true){
        std::cout << "Calibration" << std::endl;
        sprintf(command, "a");
        usb->Send(command, strlen(command));
        std::cout << "send = " << command << std::endl;
        for(int i=0; i<8; ++i) {
            printf(". ");
            sleep(1);
        }
        // }
        //コンフィギュレーション リセット
        // if(m_reset == true){
        sprintf(command, "0");
        usb->Send(command, strlen(command));        //送信
        std::cout << "send = " << command << std::endl;
        sleep(1);
        std::cout << "Gyro 0 Reset" << std::endl;
        // }
        geta = 0;
        usb->Recv(command2, 100);        //空読み バッファクリアが効かない？
        usb->ClearRecvBuf();                //バッファクリア
        return true;
    }

    void run() {
        double old_angular_z_deg = getImuData().angular_deg[2];
        double angular_z_deg = 0;
        unsigned short abnormal_count = 0;

        while (ros::ok()) {
            tf::Quaternion q;
            sensor_msgs::Imu output_msg;
            try{
                ImuData data = getImuData();
                if (data.flag == false){
                    usb->Close();
                    if(!usb->Open()) {
                        std::cerr << "reconnecting" << std::endl;
                    }
                }else{
                    output_msg.header.stamp = ros::Time::now();

                    ROS_INFO_STREAM("x_deg = " << data.angular_deg[0]);
                    ROS_INFO_STREAM("y_deg = " << data.angular_deg[1]);
                    ROS_INFO_STREAM("z_deg = " << data.angular_deg[2]);

                    if(!isInRange(std::abs(old_angular_z_deg), 180.0, 165.0) && !isInRange(std::abs(data.angular_deg[2]), 180.0, 165.0) &&
                        std::abs(old_angular_z_deg - data.angular_deg[2]) > 40 && abnormal_count < 4){

                        ROS_WARN_STREAM("Angle change too large: z = " << data.angular_deg[2]);
                        ROS_WARN_STREAM("old_z = " << old_angular_z_deg);
                        abnormal_count++;
                        continue;
                    }else{
                        abnormal_count = 0;
                        angular_z_deg = data.angular_deg[2];
                    }

                    q = tf::createQuaternionFromRPY(deg_to_rad(data.angular_deg[0]), deg_to_rad(-data.angular_deg[1]), deg_to_rad(angular_z_deg));
                    tf::quaternionTFToMsg(q, output_msg.orientation);
                    imu_pub_.publish(output_msg);
                    old_angular_z_deg = angular_z_deg;

                }
            }catch(const CheckSumError &e){
                output_msg.header.stamp = ros::Time::now();
                ROS_ERROR_STREAM(e.what());
                continue;
            }

            ros::spinOnce();
            //loop_rate.sleep();
        }
    }
};

int main(int argc, char * argv[])
{
    ros::init(argc, argv, "imu_node");
    ros::NodeHandle node;
    IMU imu(node);
    if(!imu.init()) return 1;
    imu.run();

    return 0;
}
<|endoftext|>