<commit_before>/*
 * Copyright (c) 2013 Andreas Pohl <apohl79 at gmail.com>
 *
 * This file is part of libtasks.
 *
 * libtasks is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libtasks 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libtasks.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <tasks/logging.h>
#include <sys/socket.h>
#include <cstdlib>

#include <tasks/net/uwsgi_request.h>
#include <tasks/net/socket.h>

namespace tasks {
namespace net {

std::string uwsgi_request::NO_VAL;

bool uwsgi_request::read_header(int fd) {
    socket sock(fd);
    bool success = false;
    try {
        std::size_t bytes = sock.read((char*) &m_header, sizeof(m_header));
        if (bytes == sizeof(m_header)) {
            success = true;
            tdbg("uwsgi_request::read_header: read header successfully, " << bytes << " bytes" << std::endl);
        } else {
            terr("uwsgi_request::read_header: error reading header" << std::endl);
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_header: " << e.what() << std::endl);
    }
    return success;
}

bool uwsgi_request::read_vars(int fd) {
    socket sock(fd);
    bool success = true;
    try {
        std::size_t bytes = sock.read(m_data_buffer.ptr_write(), m_data_buffer.to_write());
        if (bytes > 0) {
            m_data_buffer.move_ptr_write(bytes);
            tdbg("uwsgi_request::read_vars: read data successfully, " << bytes << " bytes" << std::endl);
        }
        if (!m_data_buffer.to_write()) {
            if (UWSGI_VARS == m_header.modifier1) {
                success = parse_vars();
                if (success) {
                    // Check if a http body needs to be read
                    std::string content_len_s = var("CONTENT_LENGTH");
                    if (NO_VAL != content_len_s) {
                        std::size_t content_len_i = std::atoi(content_len_s.c_str());
                        m_content_buffer.set_size(content_len_i);
                        m_state = READ_CONTENT;
                    } else {
                        m_state = DONE;
                    }
                }
            }
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_vars: " << e.what() << std::endl);
        success = false;
    }
    return success;
}

bool uwsgi_request::read_content(int fd) {
    socket sock(fd);
    bool success = true;
    try {
        std::size_t bytes = sock.read(m_content_buffer.ptr_write(), m_content_buffer.to_write());
        if (bytes > 0) {
            m_content_buffer.move_ptr_write(bytes);
            tdbg("uwsgi_request::read_content: read data successfully, " << bytes << " bytes" << std::endl);
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_content: " << e.what() << std::endl);
        success = false;
    }
    if (success && !m_content_buffer.to_write()) {
        m_state = DONE;
        // Move the pointer the start to enable reading from the buffer.
        //m_content_buffer.move_ptr_abs(0);
    }
    return success;
}

bool uwsgi_request::read_data(int fd) {
    bool success = true;
    if (READY == m_state) {
        m_state = READ_HEADER;
        if (success = read_header(fd)) {
            m_state = READ_DATA;
            m_data_buffer.set_size(m_header.datasize);
        }
    }
    if (success && READ_DATA == m_state) {
        success = read_vars(fd);
    }
    if (success && READ_CONTENT == m_state) {
        success = read_content(fd);
    }
    return success;
}

bool uwsgi_request::parse_vars() {
    std::size_t pos = 0;
    while (pos < m_data_buffer.size()) {
        uint16_t key_len= *((uint16_t*) m_data_buffer.ptr(pos));
        uint16_t key_start = pos + 2;
        uint16_t val_len = *((uint16_t*) m_data_buffer.ptr(key_start + key_len));
        uint16_t val_start = key_start + key_len + 2;
        if (key_len && val_len) {
            m_vars.insert(std::make_pair(std::string(m_data_buffer.ptr(key_start), key_len),
                                         std::string(m_data_buffer.ptr(val_start), val_len)));
        }
        pos = val_start + val_len;
    }
    return true;
}

} // net
} // tasks
<commit_msg>uwsgi_request.cpp: Fixed clang warning<commit_after>/*
 * Copyright (c) 2013 Andreas Pohl <apohl79 at gmail.com>
 *
 * This file is part of libtasks.
 *
 * libtasks is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libtasks 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libtasks.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <tasks/logging.h>
#include <sys/socket.h>
#include <cstdlib>

#include <tasks/net/uwsgi_request.h>
#include <tasks/net/socket.h>

namespace tasks {
namespace net {

std::string uwsgi_request::NO_VAL;

bool uwsgi_request::read_header(int fd) {
    socket sock(fd);
    bool success = false;
    try {
        std::size_t bytes = sock.read((char*) &m_header, sizeof(m_header));
        if (bytes == sizeof(m_header)) {
            success = true;
            tdbg("uwsgi_request::read_header: read header successfully, " << bytes << " bytes" << std::endl);
        } else {
            terr("uwsgi_request::read_header: error reading header" << std::endl);
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_header: " << e.what() << std::endl);
    }
    return success;
}

bool uwsgi_request::read_vars(int fd) {
    socket sock(fd);
    bool success = true;
    try {
        std::size_t bytes = sock.read(m_data_buffer.ptr_write(), m_data_buffer.to_write());
        if (bytes > 0) {
            m_data_buffer.move_ptr_write(bytes);
            tdbg("uwsgi_request::read_vars: read data successfully, " << bytes << " bytes" << std::endl);
        }
        if (!m_data_buffer.to_write()) {
            if (UWSGI_VARS == m_header.modifier1) {
                success = parse_vars();
                if (success) {
                    // Check if a http body needs to be read
                    std::string content_len_s = var("CONTENT_LENGTH");
                    if (NO_VAL != content_len_s) {
                        std::size_t content_len_i = std::atoi(content_len_s.c_str());
                        m_content_buffer.set_size(content_len_i);
                        m_state = READ_CONTENT;
                    } else {
                        m_state = DONE;
                    }
                }
            }
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_vars: " << e.what() << std::endl);
        success = false;
    }
    return success;
}

bool uwsgi_request::read_content(int fd) {
    socket sock(fd);
    bool success = true;
    try {
        std::size_t bytes = sock.read(m_content_buffer.ptr_write(), m_content_buffer.to_write());
        if (bytes > 0) {
            m_content_buffer.move_ptr_write(bytes);
            tdbg("uwsgi_request::read_content: read data successfully, " << bytes << " bytes" << std::endl);
        }
    } catch (socket_exception e) {
        terr("uwsgi_request::read_content: " << e.what() << std::endl);
        success = false;
    }
    if (success && !m_content_buffer.to_write()) {
        m_state = DONE;
        // Move the pointer the start to enable reading from the buffer.
        //m_content_buffer.move_ptr_abs(0);
    }
    return success;
}

bool uwsgi_request::read_data(int fd) {
    bool success = true;
    if (READY == m_state) {
        m_state = READ_HEADER;
        if ((success = read_header(fd))) {
            m_state = READ_DATA;
            m_data_buffer.set_size(m_header.datasize);
        }
    }
    if (success && READ_DATA == m_state) {
        success = read_vars(fd);
    }
    if (success && READ_CONTENT == m_state) {
        success = read_content(fd);
    }
    return success;
}

bool uwsgi_request::parse_vars() {
    std::size_t pos = 0;
    while (pos < m_data_buffer.size()) {
        uint16_t key_len= *((uint16_t*) m_data_buffer.ptr(pos));
        uint16_t key_start = pos + 2;
        uint16_t val_len = *((uint16_t*) m_data_buffer.ptr(key_start + key_len));
        uint16_t val_start = key_start + key_len + 2;
        if (key_len && val_len) {
            m_vars.insert(std::make_pair(std::string(m_data_buffer.ptr(key_start), key_len),
                                         std::string(m_data_buffer.ptr(val_start), val_len)));
        }
        pos = val_start + val_len;
    }
    return true;
}

} // net
} // tasks
<|endoftext|>


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

#include "util.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <vector>

#ifdef _WIN32
#include <direct.h>  // _mkdir
#endif

void Fatal(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: FATAL: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  exit(1);
}

void Warning(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: WARNING: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
}

void Error(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: error: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
}

bool CanonicalizePath(string* path, string* err) {
  // WARNING: this function is performance-critical; please benchmark
  // any changes you make to it.

  // We don't want to allocate memory if necessary; a previous version
  // of this function modified |path| as it went, which meant we
  // needed to keep a copy of it around for including in a potential
  // error message.
  //
  // Instead, we find all path components within the path, then fix
  // them up to eliminate "foo/.." pairs and "." components.  Finally,
  // we overwrite path with these new substrings (since the path only
  // ever gets shorter, we can just use memmove within it).

  const int kMaxPathComponents = 20;
  const char* starts[kMaxPathComponents];  // Starts of path components.
  int lens[kMaxPathComponents];  // Lengths of path components.

  int parts_count = 0;  // Number of entries in starts/lens.
  int slash_count = 0;  // Number of components in the original path.
  for (string::size_type start = 0; start < path->size(); ++start) {
    string::size_type end = path->find('/', start);
    if (end == string::npos)
      end = path->size();
    if (end > start) {
      if (parts_count == kMaxPathComponents) {
        *err = "can't canonicalize path '" + *path + "'; too many "
            "path components";
        return false;
      }
      starts[parts_count] = path->data() + start;
      lens[parts_count] = end - start;
      ++parts_count;
    }
    ++slash_count;
    start = end;
  }

  int i = 0;
  while (i < parts_count) {
    const char* start = starts[i];
    int len = lens[i];
    if (start[0] == '.') {
      int strip_components = 0;
      if (len == 1) {
        // "."; strip this component.
        strip_components = 1;
      } else if (len == 2 && start[1] == '.') {
        // ".."; strip this and the previous component.
        if (i == 0) {
          *err = "can't canonicalize path '" + *path + "' that reaches "
            "above its directory";
          return false;
        }
        strip_components = 2;
        --i;
      }

      if (strip_components) {
        // Shift arrays backwards to remove bad path components.
        int entries_to_move = parts_count - i - strip_components;
        memmove(starts + i, starts + i + strip_components,
                sizeof(starts[0]) * entries_to_move);
        memmove(lens + i, lens + i + strip_components,
                sizeof(lens[0]) * entries_to_move);
        parts_count -= strip_components;
        continue;
      }
    }
    ++i;
  }

  if (parts_count == slash_count)
    return true;  // Nothing to do.

  char* p = (char*)path->data();
  for (i = 0; i < parts_count; ++i) {
    if (p > path->data())
      *p++ = '/';
    int len = lens[i];
    memmove(p, starts[i], len);
    p += len;
  }
  path->resize(p - path->data());

  return true;
}

int MakeDir(const string& path) {
#ifdef _WIN32
  return _mkdir(path.c_str());
#else
  return mkdir(path.c_str(), 0777);
#endif
}
<commit_msg>Needed more path components to build Chrome. One path component in an uncommon sub-library ended up with 27 slashes in it.<commit_after>// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "util.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <vector>

#ifdef _WIN32
#include <direct.h>  // _mkdir
#endif

void Fatal(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: FATAL: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
  exit(1);
}

void Warning(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: WARNING: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
}

void Error(const char* msg, ...) {
  va_list ap;
  fprintf(stderr, "ninja: error: ");
  va_start(ap, msg);
  vfprintf(stderr, msg, ap);
  va_end(ap);
  fprintf(stderr, "\n");
}

bool CanonicalizePath(string* path, string* err) {
  // WARNING: this function is performance-critical; please benchmark
  // any changes you make to it.

  // We don't want to allocate memory if necessary; a previous version
  // of this function modified |path| as it went, which meant we
  // needed to keep a copy of it around for including in a potential
  // error message.
  //
  // Instead, we find all path components within the path, then fix
  // them up to eliminate "foo/.." pairs and "." components.  Finally,
  // we overwrite path with these new substrings (since the path only
  // ever gets shorter, we can just use memmove within it).

  const int kMaxPathComponents = 30;
  const char* starts[kMaxPathComponents];  // Starts of path components.
  int lens[kMaxPathComponents];  // Lengths of path components.

  int parts_count = 0;  // Number of entries in starts/lens.
  int slash_count = 0;  // Number of components in the original path.
  for (string::size_type start = 0; start < path->size(); ++start) {
    string::size_type end = path->find('/', start);
    if (end == string::npos)
      end = path->size();
    if (end > start) {
      if (parts_count == kMaxPathComponents) {
        *err = "can't canonicalize path '" + *path + "'; too many "
            "path components";
        return false;
      }
      starts[parts_count] = path->data() + start;
      lens[parts_count] = end - start;
      ++parts_count;
    }
    ++slash_count;
    start = end;
  }

  int i = 0;
  while (i < parts_count) {
    const char* start = starts[i];
    int len = lens[i];
    if (start[0] == '.') {
      int strip_components = 0;
      if (len == 1) {
        // "."; strip this component.
        strip_components = 1;
      } else if (len == 2 && start[1] == '.') {
        // ".."; strip this and the previous component.
        if (i == 0) {
          *err = "can't canonicalize path '" + *path + "' that reaches "
            "above its directory";
          return false;
        }
        strip_components = 2;
        --i;
      }

      if (strip_components) {
        // Shift arrays backwards to remove bad path components.
        int entries_to_move = parts_count - i - strip_components;
        memmove(starts + i, starts + i + strip_components,
                sizeof(starts[0]) * entries_to_move);
        memmove(lens + i, lens + i + strip_components,
                sizeof(lens[0]) * entries_to_move);
        parts_count -= strip_components;
        continue;
      }
    }
    ++i;
  }

  if (parts_count == slash_count)
    return true;  // Nothing to do.

  char* p = (char*)path->data();
  for (i = 0; i < parts_count; ++i) {
    if (p > path->data())
      *p++ = '/';
    int len = lens[i];
    memmove(p, starts[i], len);
    p += len;
  }
  path->resize(p - path->data());

  return true;
}

int MakeDir(const string& path) {
#ifdef _WIN32
  return _mkdir(path.c_str());
#else
  return mkdir(path.c_str(), 0777);
#endif
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
 *  Copyright (C) 2018 Clifford Wolf <dave@ds0.me>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthEcp5Pass : public ScriptPass
{
	SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { }

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_ecp5 [options]\n");
		log("\n");
		log("This command runs synthesis for ECP5 FPGAs.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module\n");
		log("\n");
		log("    -blif <file>\n");
		log("        write the design to the specified BLIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified EDIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -json <file>\n");
		log("        write the design to the specified JSON file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -noflatten\n");
		log("        do not flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("    -noccu2\n");
		log("        do not use CCU2 cells in output netlist\n");
		log("\n");
		log("    -nodffe\n");
		log("        do not use flipflops with CE in output netlist\n");
		log("\n");
		log("    -nobram\n");
		log("        do not use BRAM cells in output netlist\n");
		log("\n");
		log("    -nodram\n");
		log("        do not use distributed RAM cells in output netlist\n");
		log("\n");
		log("    -nomux\n");
		log("        do not use PFU muxes to implement LUTs larger than LUT4s\n");
		log("\n");
		log("    -abc2\n");
		log("        run two passes of 'abc' for slightly improved logic density\n");
		log("\n");
		log("    -vpr\n");
		log("        generate an output netlist (and BLIF file) suitable for VPR\n");
		log("        (this feature is experimental and incomplete)\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	string top_opt, blif_file, edif_file, json_file;
	bool noccu2, nodffe, nobram, nodram, nomux, flatten, retime, abc2, vpr;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		blif_file = "";
		edif_file = "";
		json_file = "";
		noccu2 = false;
		nodffe = false;
		nobram = false;
		nodram = false;
		nomux = false;
		flatten = true;
		retime = false;
		abc2 = false;
		vpr = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-blif" && argidx+1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-json" && argidx+1 < args.size()) {
				json_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			if (args[argidx] == "-flatten") {
				flatten = true;
				continue;
			}
			if (args[argidx] == "-noflatten") {
				flatten = false;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			if (args[argidx] == "-noccu2") {
				noccu2 = true;
				continue;
			}
			if (args[argidx] == "-nodffe") {
				nodffe = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-nodram") {
				nodram = true;
				continue;
			}
			if (args[argidx] == "-nomux") {
				nomux = true;
				continue;
			}
			if (args[argidx] == "-abc2") {
				abc2 = true;
				continue;
			}
			if (args[argidx] == "-vpr") {
				vpr = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");

		log_header(design, "Executing SYNTH_ECP5 pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin"))
		{
			run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
		}

		if (flatten && check_label("flatten", "(unless -noflatten)"))
		{
			run("proc");
			run("flatten");
			run("tribuf -logic");
			run("deminout");
		}

		if (check_label("coarse"))
		{
			run("synth -run coarse");
		}

		if (!nobram && check_label("bram", "(skip if -nobram)"))
		{
			run("memory_bram -rules +/ecp5/bram.txt");
			run("techmap -map +/ecp5/brams_map.v");
		}

		if (!nodram && check_label("dram", "(skip if -nodram)"))
		{
			run("memory_bram -rules +/ecp5/dram.txt");
			run("techmap -map +/ecp5/drams_map.v");
		}

		if (check_label("fine"))
		{
			run("opt -fast -mux_undef -undriven -fine");
			run("memory_map");
			run("opt -undriven -fine");
			if (noccu2)
				run("techmap");
			else
				run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
			if (retime || help_mode)
				run("abc -dff", "(only if -retime)");
		}

		if (check_label("map_ffs"))
		{
			run("dffsr2dff");
			run("dff2dffs");
			run("opt_clean");
			if (!nodffe)
				run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
			run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
			run("opt_expr -undriven -mux_undef");
			run("simplemap");
			run("ecp5_ffinit");
		}

		if (check_label("map_luts"))
		{
			if (abc2 || help_mode) {
				run("abc", "      (only if -abc2)");
			}
			run("techmap -map +/ecp5/latches_map.v");
			if (nomux)
				run("abc -lut 4 -dress");
			else
				run("abc -lut 4:7 -dress");
			run("clean");
		}

		if (check_label("map_cells"))
		{
			if (vpr)
				run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
			else
				run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");

			run("clean");
		}

		if (check_label("check"))
		{
			run("hierarchy -check");
			run("stat");
			run("check -noinit");
		}

		if (check_label("blif"))
		{
			if (!blif_file.empty() || help_mode) {
				if (vpr || help_mode) {
					run(stringf("opt_clean -purge"),
							"                                 (vpr mode)");
					run(stringf("write_blif -attr -cname -conn -param %s",
							help_mode ? "<file-name>" : blif_file.c_str()),
							" (vpr mode)");
				}
				if (!vpr)
					run(stringf("write_blif -gates -attr -param %s",
							help_mode ? "<file-name>" : blif_file.c_str()),
							"       (non-vpr mode)");
			}
		}

		if (check_label("edif"))
		{
			if (!edif_file.empty() || help_mode)
				run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
		}

		if (check_label("json"))
		{
			if (!json_file.empty() || help_mode)
				run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
		}
	}
} SynthEcp5Pass;

PRIVATE_NAMESPACE_END
<commit_msg>synth_ecp5 rename -nomux to -nowidelut, but preserve former<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
 *  Copyright (C) 2018 Clifford Wolf <dave@ds0.me>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/rtlil.h"
#include "kernel/log.h"

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SynthEcp5Pass : public ScriptPass
{
	SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { }

	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    synth_ecp5 [options]\n");
		log("\n");
		log("This command runs synthesis for ECP5 FPGAs.\n");
		log("\n");
		log("    -top <module>\n");
		log("        use the specified module as top module\n");
		log("\n");
		log("    -blif <file>\n");
		log("        write the design to the specified BLIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -edif <file>\n");
		log("        write the design to the specified EDIF file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -json <file>\n");
		log("        write the design to the specified JSON file. writing of an output file\n");
		log("        is omitted if this parameter is not specified.\n");
		log("\n");
		log("    -run <from_label>:<to_label>\n");
		log("        only run the commands between the labels (see below). an empty\n");
		log("        from label is synonymous to 'begin', and empty to label is\n");
		log("        synonymous to the end of the command list.\n");
		log("\n");
		log("    -noflatten\n");
		log("        do not flatten design before synthesis\n");
		log("\n");
		log("    -retime\n");
		log("        run 'abc' with -dff option\n");
		log("\n");
		log("    -noccu2\n");
		log("        do not use CCU2 cells in output netlist\n");
		log("\n");
		log("    -nodffe\n");
		log("        do not use flipflops with CE in output netlist\n");
		log("\n");
		log("    -nobram\n");
		log("        do not use BRAM cells in output netlist\n");
		log("\n");
		log("    -nodram\n");
		log("        do not use distributed RAM cells in output netlist\n");
		log("\n");
		log("    -nowidelut\n");
		log("        do not use PFU muxes to implement LUTs larger than LUT4s\n");
		log("\n");
		log("    -abc2\n");
		log("        run two passes of 'abc' for slightly improved logic density\n");
		log("\n");
		log("    -vpr\n");
		log("        generate an output netlist (and BLIF file) suitable for VPR\n");
		log("        (this feature is experimental and incomplete)\n");
		log("\n");
		log("\n");
		log("The following commands are executed by this synthesis command:\n");
		help_script();
		log("\n");
	}

	string top_opt, blif_file, edif_file, json_file;
	bool noccu2, nodffe, nobram, nodram, nowidelut, flatten, retime, abc2, vpr;

	void clear_flags() YS_OVERRIDE
	{
		top_opt = "-auto-top";
		blif_file = "";
		edif_file = "";
		json_file = "";
		noccu2 = false;
		nodffe = false;
		nobram = false;
		nodram = false;
		nowidelut = false;
		flatten = true;
		retime = false;
		abc2 = false;
		vpr = false;
	}

	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string run_from, run_to;
		clear_flags();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++)
		{
			if (args[argidx] == "-top" && argidx+1 < args.size()) {
				top_opt = "-top " + args[++argidx];
				continue;
			}
			if (args[argidx] == "-blif" && argidx+1 < args.size()) {
				blif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-edif" && argidx+1 < args.size()) {
				edif_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-json" && argidx+1 < args.size()) {
				json_file = args[++argidx];
				continue;
			}
			if (args[argidx] == "-run" && argidx+1 < args.size()) {
				size_t pos = args[argidx+1].find(':');
				if (pos == std::string::npos)
					break;
				run_from = args[++argidx].substr(0, pos);
				run_to = args[argidx].substr(pos+1);
				continue;
			}
			if (args[argidx] == "-flatten") {
				flatten = true;
				continue;
			}
			if (args[argidx] == "-noflatten") {
				flatten = false;
				continue;
			}
			if (args[argidx] == "-retime") {
				retime = true;
				continue;
			}
			if (args[argidx] == "-noccu2") {
				noccu2 = true;
				continue;
			}
			if (args[argidx] == "-nodffe") {
				nodffe = true;
				continue;
			}
			if (args[argidx] == "-nobram") {
				nobram = true;
				continue;
			}
			if (args[argidx] == "-nodram") {
				nodram = true;
				continue;
			}
			if (args[argidx] == "-nowidelut" || args[argidx] == "-nomux") {
				nowidelut = true;
				continue;
			}
			if (args[argidx] == "-abc2") {
				abc2 = true;
				continue;
			}
			if (args[argidx] == "-vpr") {
				vpr = true;
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		if (!design->full_selection())
			log_cmd_error("This command only operates on fully selected designs!\n");

		log_header(design, "Executing SYNTH_ECP5 pass.\n");
		log_push();

		run_script(design, run_from, run_to);

		log_pop();
	}

	void script() YS_OVERRIDE
	{
		if (check_label("begin"))
		{
			run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v");
			run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str()));
		}

		if (flatten && check_label("flatten", "(unless -noflatten)"))
		{
			run("proc");
			run("flatten");
			run("tribuf -logic");
			run("deminout");
		}

		if (check_label("coarse"))
		{
			run("synth -run coarse");
		}

		if (!nobram && check_label("bram", "(skip if -nobram)"))
		{
			run("memory_bram -rules +/ecp5/bram.txt");
			run("techmap -map +/ecp5/brams_map.v");
		}

		if (!nodram && check_label("dram", "(skip if -nodram)"))
		{
			run("memory_bram -rules +/ecp5/dram.txt");
			run("techmap -map +/ecp5/drams_map.v");
		}

		if (check_label("fine"))
		{
			run("opt -fast -mux_undef -undriven -fine");
			run("memory_map");
			run("opt -undriven -fine");
			if (noccu2)
				run("techmap");
			else
				run("techmap -map +/techmap.v -map +/ecp5/arith_map.v");
			if (retime || help_mode)
				run("abc -dff", "(only if -retime)");
		}

		if (check_label("map_ffs"))
		{
			run("dffsr2dff");
			run("dff2dffs");
			run("opt_clean");
			if (!nodffe)
				run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
			run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
			run("opt_expr -undriven -mux_undef");
			run("simplemap");
			run("ecp5_ffinit");
		}

		if (check_label("map_luts"))
		{
			if (abc2 || help_mode) {
				run("abc", "      (only if -abc2)");
			}
			run("techmap -map +/ecp5/latches_map.v");
			if (nowidelut)
				run("abc -lut 4 -dress");
			else
				run("abc -lut 4:7 -dress");
			run("clean");
		}

		if (check_label("map_cells"))
		{
			if (vpr)
				run("techmap -D NO_LUT -map +/ecp5/cells_map.v");
			else
				run("techmap -map +/ecp5/cells_map.v", "(with -D NO_LUT in vpr mode)");

			run("clean");
		}

		if (check_label("check"))
		{
			run("hierarchy -check");
			run("stat");
			run("check -noinit");
		}

		if (check_label("blif"))
		{
			if (!blif_file.empty() || help_mode) {
				if (vpr || help_mode) {
					run(stringf("opt_clean -purge"),
							"                                 (vpr mode)");
					run(stringf("write_blif -attr -cname -conn -param %s",
							help_mode ? "<file-name>" : blif_file.c_str()),
							" (vpr mode)");
				}
				if (!vpr)
					run(stringf("write_blif -gates -attr -param %s",
							help_mode ? "<file-name>" : blif_file.c_str()),
							"       (non-vpr mode)");
			}
		}

		if (check_label("edif"))
		{
			if (!edif_file.empty() || help_mode)
				run(stringf("write_edif %s", help_mode ? "<file-name>" : edif_file.c_str()));
		}

		if (check_label("json"))
		{
			if (!json_file.empty() || help_mode)
				run(stringf("write_json %s", help_mode ? "<file-name>" : json_file.c_str()));
		}
	}
} SynthEcp5Pass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>
#include "var.hpp"

genotype::~genotype(){}

zvar::~zvar(){}

void zvar::setPopName(string  popName){
  name = popName;
}

pooled::~pooled(){}

double pooled::bound(double v){
  if(v <= 0.00001){
    return  0.00001;
  }
  if(v >= 0.99999){
    return 0.99999;
  }
  return v;
}

gl::~gl(){}

gl::gl(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;
}

pl::~pl(){}

pl::pl(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

gp::~gp(){}

gp::gp(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

gt::~gt(){}

gt::gt(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

pooled::pooled(void){

  npop   = 0;
  afsum  = 0;
  nalt   = 0;
  nref   = 0;
  af     = 0;
  npop   = 0;
  ntot   = 0;

  alpha  = 0.01;
  beta   = 0.01;

}

// polymorphism for GL and PL

double gt::unphred(map< string, vector<string> > & geno, int index){
  return -1;
}

double gl::unphred(map< string, vector<string> > & geno, int index){

  double unphreded = atof(geno["GL"][index].c_str());
  return unphreded;
}

double gp::unphred(map< string, vector<string> > & geno, int index){

  double unphreded = atof(geno["GP"][index].c_str());
  return log(unphreded) ;
}

double pl::unphred(map< string, vector<string> > & geno, int index){

   double unphreded = atof(geno["PL"][index].c_str());

   unphreded = log(pow(10, (-unphreded/10)));

   return unphreded;
}

void pooled::loadPop(vector< map< string, vector<string> > > & group, string seqid, long int position){
  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    string genotype = (*targ_it)["GT"].front();

    if(genotype == "./."){
      continue;
    }

    string allelecounts = (*targ_it)["AD"].front();

    vector<string> ac   = (*targ_it)["AD"];

    npop += 1;

    double af = atof(ac[1].c_str()) / ( atof(ac[0].c_str()) + atof(ac[1].c_str()) );

    if(atof(ac[1].c_str()) == 0){
      af = 0;
    }
    if(atof(ac[0].c_str()) == 0){
      af = 1;
    }

    afsum += af;

    afs.push_back(af);

    nrefs.push_back(atof(ac[0].c_str()));
    nalts.push_back(atof(ac[1].c_str()));

    nref += atof(ac[0].c_str());
    ntot += atof(ac[0].c_str());
    nalt += atof(ac[1].c_str());
    ntot += atof(ac[1].c_str());
  }
  if(npop < 1){
    af = -1;
  }
  else{
    af = afsum / npop;
  }
}

void genotype::estimatePosterior(void){

  int ng = genoIndex.size();

  for(int i = 0 ; i < ng; i++){

    if(genoIndex[i] == -1){
      continue;
    }

    double aa = genoLikelihoods[i][0] ;
    double ab = genoLikelihoods[i][1] ;
    double bb = genoLikelihoods[i][2] ;

    alpha += exp(ab);
    beta  += exp(ab);

    alpha += 2 * exp(aa);
    beta  += 2 * exp(bb);
  }

}

void pooled::estimatePosterior(void){

  if(npop < 2){
    cerr << "FATAL: not enough pooled populations in the target or background\n";
    exit(1);
  }

  double xbar = af;
  double ss = 0;

  for(int i = 0 ; i < npop; i++){
    ss += pow(( afs[i] - xbar),2);
  }

  double var = (1/(npop-1))*ss;

  xbar = bound(xbar);
  if(var < 0.01){
    var = 0.01;
  }
  if(var < xbar*(1-xbar)){
    alpha = xbar * (((xbar*(1-xbar))/var) -1);
    beta  = (1 - xbar) * (((xbar*(1-xbar))/var) -1);
  }
  else{
    alpha = -1;
    beta  = -1;
  }
}

void genotype::loadPop( vector< map< string, vector<string> > >& group, string seqid, long int position){

  seqid = seqid;
  pos   = position  ;

  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    string genotype = (*targ_it)["GT"].front();

    if(genotype == "./0" || genotype == "./1" || genotype == "."){
      genotype = "./.";
    }

    gts.push_back(genotype);

    vector<double> phreds;
    vector<double> phredsCDF;

    double sum  = 0;
    if(genotype != "./."){

      double pa  =  unphred( (*targ_it), 0)  ;
      double pab =  unphred( (*targ_it), 1)  ;
      double pbb =  unphred( (*targ_it), 2)  ;

      double norm = log(exp(pa) + exp(pab) + exp(pbb))  ;

      phreds.push_back(pa  - norm);
      phreds.push_back(pab - norm);
      phreds.push_back(pbb - norm);

      sum += exp(pa - norm);
      //      cerr << sum << endl;
      phredsCDF.push_back(sum);
      sum += exp(pab - norm);
      //      cerr << sum << endl;
      phredsCDF.push_back(sum);
      sum += exp(pbb - norm);
      //      cerr << sum << endl;
      //      cerr << endl;
      phredsCDF.push_back(sum);
    }
    else{
      phreds.push_back(log(1/3));
      phreds.push_back(log(1/3));
      phreds.push_back(log(1/3));
      phredsCDF.push_back(1/3);
      phredsCDF.push_back(2/3);
      phredsCDF.push_back(1);
    }

    genoLikelihoods.push_back(phreds);
    genoLikelihoodsCDF.push_back(phredsCDF);

    while(1){
      if(genotype == "./."){
        genoIndex.push_back(-1);
        break;
      }
      if(genotype == "0/0"){
        ngeno += 1;
        nhomr += 1;
        nref  += 2;
        genoIndex.push_back(0);
        break;
      }
      if(genotype == "0/1"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1/0"){
        ngeno += 1;
        nhet  += 1;
	nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1/1"){
	ngeno += 1;
        nhoma += 1;
        nalt  += 2;
        genoIndex.push_back(2);
        break;
      }
      if(genotype == "0|0"){
        ngeno += 1;
        nhomr += 1;
        nref  += 2;
        genoIndex.push_back(0);
        break;
      }
      if(genotype == "0|1"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1|0"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1|1"){
        ngeno += 1;
        nhoma += 1;
        nalt  += 2;
        genoIndex.push_back(2);
        break;
      }
      cerr << "FATAL: unknown genotype: " << genotype << endl;
      exit(1);
    }
  }
  if(nalt == 0 && nref == 0){
    af = -1;
  }
  else{
    af  = (nalt / (nref + nalt));

    if(nhet > 0){
      fis = ( 1 - ((nhet/ngeno) / (2*af*(1 - af))));
    }
    else{
      fis = 1;
    }
    if(fis < 0){
      fis = 0.00001;
    }
  }
  hfrq = nhet / ngeno;
  npop = ngeno;
}
<commit_msg>Copyright header<commit_after>/*
    vcflib C++ library for parsing and manipulating VCF files

    Copyright © 2010-2020 Erik Garrison
    Copyright © 2020      Pjotr Prins
    Copyright © 2014      Zev N. Kronenberg

    This software is published under the MIT License. See the LICENSE file.
*/

#include "var.hpp"

genotype::~genotype(){}

zvar::~zvar(){}

void zvar::setPopName(string  popName){
  name = popName;
}

pooled::~pooled(){}

double pooled::bound(double v){
  if(v <= 0.00001){
    return  0.00001;
  }
  if(v >= 0.99999){
    return 0.99999;
  }
  return v;
}

gl::~gl(){}

gl::gl(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;
}

pl::~pl(){}

pl::pl(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

gp::~gp(){}

gp::gp(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

gt::~gt(){}

gt::gt(void){
  nalt  = 0;
  nref  = 0;
  af    = 0;
  nhomr = 0;
  nhoma = 0;
  nhet  = 0;
  ngeno = 0;
  fis   = 0;
  hfrq  = 0;

  alpha = 0.01;
  beta  = 0.01;

}

pooled::pooled(void){

  npop   = 0;
  afsum  = 0;
  nalt   = 0;
  nref   = 0;
  af     = 0;
  npop   = 0;
  ntot   = 0;

  alpha  = 0.01;
  beta   = 0.01;

}

// polymorphism for GL and PL

double gt::unphred(map< string, vector<string> > & geno, int index){
  return -1;
}

double gl::unphred(map< string, vector<string> > & geno, int index){

  double unphreded = atof(geno["GL"][index].c_str());
  return unphreded;
}

double gp::unphred(map< string, vector<string> > & geno, int index){

  double unphreded = atof(geno["GP"][index].c_str());
  return log(unphreded) ;
}

double pl::unphred(map< string, vector<string> > & geno, int index){

   double unphreded = atof(geno["PL"][index].c_str());

   unphreded = log(pow(10, (-unphreded/10)));

   return unphreded;
}

void pooled::loadPop(vector< map< string, vector<string> > > & group, string seqid, long int position){
  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    string genotype = (*targ_it)["GT"].front();

    if(genotype == "./."){
      continue;
    }

    string allelecounts = (*targ_it)["AD"].front();

    vector<string> ac   = (*targ_it)["AD"];

    npop += 1;

    double af = atof(ac[1].c_str()) / ( atof(ac[0].c_str()) + atof(ac[1].c_str()) );

    if(atof(ac[1].c_str()) == 0){
      af = 0;
    }
    if(atof(ac[0].c_str()) == 0){
      af = 1;
    }

    afsum += af;

    afs.push_back(af);

    nrefs.push_back(atof(ac[0].c_str()));
    nalts.push_back(atof(ac[1].c_str()));

    nref += atof(ac[0].c_str());
    ntot += atof(ac[0].c_str());
    nalt += atof(ac[1].c_str());
    ntot += atof(ac[1].c_str());
  }
  if(npop < 1){
    af = -1;
  }
  else{
    af = afsum / npop;
  }
}

void genotype::estimatePosterior(void){

  int ng = genoIndex.size();

  for(int i = 0 ; i < ng; i++){

    if(genoIndex[i] == -1){
      continue;
    }

    double aa = genoLikelihoods[i][0] ;
    double ab = genoLikelihoods[i][1] ;
    double bb = genoLikelihoods[i][2] ;

    alpha += exp(ab);
    beta  += exp(ab);

    alpha += 2 * exp(aa);
    beta  += 2 * exp(bb);
  }

}

void pooled::estimatePosterior(void){

  if(npop < 2){
    cerr << "FATAL: not enough pooled populations in the target or background\n";
    exit(1);
  }

  double xbar = af;
  double ss = 0;

  for(int i = 0 ; i < npop; i++){
    ss += pow(( afs[i] - xbar),2);
  }

  double var = (1/(npop-1))*ss;

  xbar = bound(xbar);
  if(var < 0.01){
    var = 0.01;
  }
  if(var < xbar*(1-xbar)){
    alpha = xbar * (((xbar*(1-xbar))/var) -1);
    beta  = (1 - xbar) * (((xbar*(1-xbar))/var) -1);
  }
  else{
    alpha = -1;
    beta  = -1;
  }
}

void genotype::loadPop( vector< map< string, vector<string> > >& group, string seqid, long int position){

  seqid = seqid;
  pos   = position  ;

  vector< map< string, vector<string> > >::iterator targ_it = group.begin();

  for(; targ_it != group.end(); targ_it++){

    string genotype = (*targ_it)["GT"].front();

    if(genotype == "./0" || genotype == "./1" || genotype == "."){
      genotype = "./.";
    }

    gts.push_back(genotype);

    vector<double> phreds;
    vector<double> phredsCDF;

    double sum  = 0;
    if(genotype != "./."){

      double pa  =  unphred( (*targ_it), 0)  ;
      double pab =  unphred( (*targ_it), 1)  ;
      double pbb =  unphred( (*targ_it), 2)  ;

      double norm = log(exp(pa) + exp(pab) + exp(pbb))  ;

      phreds.push_back(pa  - norm);
      phreds.push_back(pab - norm);
      phreds.push_back(pbb - norm);

      sum += exp(pa - norm);
      //      cerr << sum << endl;
      phredsCDF.push_back(sum);
      sum += exp(pab - norm);
      //      cerr << sum << endl;
      phredsCDF.push_back(sum);
      sum += exp(pbb - norm);
      //      cerr << sum << endl;
      //      cerr << endl;
      phredsCDF.push_back(sum);
    }
    else{
      phreds.push_back(log(1/3));
      phreds.push_back(log(1/3));
      phreds.push_back(log(1/3));
      phredsCDF.push_back(1/3);
      phredsCDF.push_back(2/3);
      phredsCDF.push_back(1);
    }

    genoLikelihoods.push_back(phreds);
    genoLikelihoodsCDF.push_back(phredsCDF);

    while(1){
      if(genotype == "./."){
        genoIndex.push_back(-1);
        break;
      }
      if(genotype == "0/0"){
        ngeno += 1;
        nhomr += 1;
        nref  += 2;
        genoIndex.push_back(0);
        break;
      }
      if(genotype == "0/1"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1/0"){
        ngeno += 1;
        nhet  += 1;
	nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1/1"){
	ngeno += 1;
        nhoma += 1;
        nalt  += 2;
        genoIndex.push_back(2);
        break;
      }
      if(genotype == "0|0"){
        ngeno += 1;
        nhomr += 1;
        nref  += 2;
        genoIndex.push_back(0);
        break;
      }
      if(genotype == "0|1"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1|0"){
        ngeno += 1;
        nhet  += 1;
        nref  += 1;
        nalt  += 1;
        genoIndex.push_back(1);
        break;
      }
      if(genotype == "1|1"){
        ngeno += 1;
        nhoma += 1;
        nalt  += 2;
        genoIndex.push_back(2);
        break;
      }
      cerr << "FATAL: unknown genotype: " << genotype << endl;
      exit(1);
    }
  }
  if(nalt == 0 && nref == 0){
    af = -1;
  }
  else{
    af  = (nalt / (nref + nalt));

    if(nhet > 0){
      fis = ( 1 - ((nhet/ngeno) / (2*af*(1 - af))));
    }
    else{
      fis = 1;
    }
    if(fis < 0){
      fis = 0.00001;
    }
  }
  hfrq = nhet / ngeno;
  npop = ngeno;
}
<|endoftext|>


<commit_before>
#include <cmath>
#include <chrono>
#include <random>
#include <vector>
#include <cassert>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>

#include "caf/all.hpp"

#include "vast/coder.hpp"
#include "vast/operator.hpp"
#include "vast/wah_bitmap.hpp"
#include "vast/bitmap_index.hpp"

#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/coder.hpp"
#include "vast/concept/printable/vast/bitmap.hpp"

using namespace std;
using namespace std::chrono;
using namespace caf;
using namespace vast;

class config : public actor_system_config {
public:
  string filename = "";
  uint32_t bound = 0;
  bool print_results;
  config() {
    opt_group{custom_options_, "global"}
    .add(filename, "data-file,f", "File with test data (one value per line)")
    .add(bound, "bound,b", "maximum value (0 will scan values)")
    .add(print_results, "print,p", "print resulting bitmap index");
  }
};

void caf_main(actor_system&, const config& cfg) {
  vector<uint32_t> values;
  if (cfg.filename.empty()) {
    values = {10,  7, 22,  6,  7,  1,  9, 42,  2,  5,
              13,  3,  2,  1,  0,  1, 18, 18,  3, 13,
               5,  9,  0,  3,  2, 19,  5, 23, 22, 10,
               6, 22};
  } else {
    cout << "Reading data from '" << cfg.filename << "' ... " << flush;
    ifstream source{cfg.filename, std::ios::in};
    uint32_t next;
    while (source >> next) {
      values.push_back(next);
    }
  }
  auto amount = values.size();
  cout << "'" << amount << "' values." << endl;
  auto bound = cfg.bound;
  if (bound == 0 && amount > 0) {
    auto itr = max_element(values.begin(), values.end());
    bound = *itr;
  }
  cout << "Maximum value is '" << bound << "'." << endl;

  /*
  // Extract key set
  vector<uint32_t> keys = values;
  std::sort(keys.begin(), keys.end());
  auto last = std::unique(keys.begin(), keys.end());
  keys.erase(last, end(keys));
  */

  auto start = high_resolution_clock::now();
  bitmap_index<uint32_t, equality_coder<wah_bitmap>> bmi{bound + 1};
  for (auto& val : values)
    bmi.push_back(val);
  auto stop = high_resolution_clock::now();

  if (cfg.print_results) {
    // print index by key
    auto& coder = bmi.coder();
    cout << coder << endl;
    /*
    auto& storage = coder.storage();
    for (auto& key : keys)
      cout << "Index for value " << key << ":" << endl
           << storage[key] << endl;
    */
  }
  cout << "Time: '"
       << duration_cast<milliseconds>(stop - start).count()
       << "' ms" << endl;
}

CAF_MAIN()
<commit_msg>Remove ambiguity of std::vector and VAST define<commit_after>
#include <cmath>
#include <chrono>
#include <random>
#include <vector>
#include <cassert>
#include <fstream>
#include <iomanip>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>

#include "caf/all.hpp"

#include "vast/coder.hpp"
#include "vast/operator.hpp"
#include "vast/wah_bitmap.hpp"
#include "vast/bitmap_index.hpp"

#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/to_string.hpp"
#include "vast/concept/printable/vast/coder.hpp"
#include "vast/concept/printable/vast/bitmap.hpp"

using namespace std;
using namespace std::chrono;
using namespace caf;
using namespace vast;

class config : public actor_system_config {
public:
  string filename = "";
  uint32_t bound = 0;
  bool print_results;
  config() {
    opt_group{custom_options_, "global"}
    .add(filename, "data-file,f", "File with test data (one value per line)")
    .add(bound, "bound,b", "maximum value (0 will scan values)")
    .add(print_results, "print,p", "print resulting bitmap index");
  }
};

void caf_main(actor_system&, const config& cfg) {
  std::vector<uint32_t> values;
  if (cfg.filename.empty()) {
    values = {10,  7, 22,  6,  7,  1,  9, 42,  2,  5,
              13,  3,  2,  1,  0,  1, 18, 18,  3, 13,
               5,  9,  0,  3,  2, 19,  5, 23, 22, 10,
               6, 22};
  } else {
    cout << "Reading data from '" << cfg.filename << "' ... " << flush;
    ifstream source{cfg.filename, std::ios::in};
    uint32_t next;
    while (source >> next) {
      values.push_back(next);
    }
  }
  auto amount = values.size();
  cout << "'" << amount << "' values." << endl;
  auto bound = cfg.bound;
  if (bound == 0 && amount > 0) {
    auto itr = max_element(values.begin(), values.end());
    bound = *itr;
  }
  cout << "Maximum value is '" << bound << "'." << endl;

  /*
  // Extract key set
  vector<uint32_t> keys = values;
  std::sort(keys.begin(), keys.end());
  auto last = std::unique(keys.begin(), keys.end());
  keys.erase(last, end(keys));
  */

  auto start = high_resolution_clock::now();
  bitmap_index<uint32_t, equality_coder<wah_bitmap>> bmi{bound + 1};
  for (auto& val : values)
    bmi.push_back(val);
  auto stop = high_resolution_clock::now();

  if (cfg.print_results) {
    // print index by key
    auto& coder = bmi.coder();
    cout << coder << endl;
    /*
    auto& storage = coder.storage();
    for (auto& key : keys)
      cout << "Index for value " << key << ":" << endl
           << storage[key] << endl;
    */
  }
  cout << "Time: '"
       << duration_cast<milliseconds>(stop - start).count()
       << "' ms" << endl;
}

CAF_MAIN()
<|endoftext|>


<commit_before>/*
 * NotebookCache.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "SessionRnbParser.hpp"
#include "NotebookCache.hpp"
#include "NotebookChunkDefs.hpp"
#include "NotebookPaths.hpp"
#include "NotebookOutput.hpp"
#include "NotebookHtmlWidgets.hpp"

#include <boost/foreach.hpp>

#include <session/SessionUserSettings.hpp>
#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>

#include <core/Algorithm.hpp>

#include <r/RExec.hpp>
#include <r/RRoutines.hpp>

// The version identifier for the cache format. Changing this invalidates old
// caches, and should be done only when making breaking changes to the
// cache format.
#define kCacheVersion "1"

#define kCacheAgeThresholdMs 1000 * 60 * 60 * 24 * 2

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

// it's much faster to load a notebook from its cache than it is to rehydrate
// it from its .Rnb, so we keep it around even if the document is closed (as
// it's somewhat common to open and close a document periodically over the
// course of working on a project, and it's nice when it opens quickly).
//
// however, we don't want to keep the cache around *forever* just in case we
// might need it, as it can be quite large. as a compromise, an unused cache
// hangs around for a couple of days, then gets automatically swept up by this
// function.
void cleanUnusedCaches()
{
   FilePath cacheRoot = notebookCacheRoot();
   if (!cacheRoot.exists())
      return;

   std::vector<FilePath> caches;
   Error error = cacheRoot.children(&caches);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   std::string nbCtxId = notebookCtxId();
   BOOST_FOREACH(const FilePath cache, caches)
   {
      // make sure this looks like a notebook cache
      if (!cache.isDirectory())
         continue;
      std::vector<std::string> parts = core::algorithm::split(
            cache.stem(), "-");
      if (parts.size() < 2)
         continue;

      // get the path of the notebook associated with the cache
      FilePath path;
      error = notebookIdToPath(parts[0], &path);
      if (error)
      {
         if (error.code() == boost::system::errc::no_such_file_or_directory)
         {
            // we have no idea what notebook this cache is for, so it's
            // unusable; delete it
            error = cache.remove();
            if (error)
               LOG_ERROR(error);
         }
         else
         {
            LOG_ERROR(error);
         }

         continue;
      }

      // is this document still open? if so, leave the cache alone.
      std::string id;
      source_database::getId(module_context::createAliasedPath(
               FileInfo(path)), &id);
      if (!id.empty())
      {
         continue;
      }

      std::vector<FilePath> contexts;
      error = cache.complete(kCacheVersion).children(&contexts);
      if (error)
      {
         LOG_ERROR(error);
         continue;
      }

      BOOST_FOREACH(const FilePath context, contexts)
      {
         // skip if not our context or the saved context
         if (context.filename() != kSavedCtx &&
             context.filename() != nbCtxId)
            continue;

         // check the write time on the chunk defs file (updated when the doc is
         // mutated or saved)
         FilePath chunkDefs = context.complete(kNotebookChunkDefFilename);
         if (!chunkDefs.exists())
            continue;
         if ((std::time(NULL) - chunkDefs.lastWriteTime()) > kCacheAgeThresholdMs)
         {
            // the cache is old and the document hasn't been opened in a while --
            // remove it.
            error = context.remove();
            if (error)
               LOG_ERROR(error);
         }
      }
   }
}

Error removeStaleSavedChunks(FilePath& docPath, FilePath& cachePath)
{
   Error error;
   if (!cachePath.exists())
      return Success();

   // extract the set of chunk IDs from the definition files
   json::Value oldDefs;
   json::Value newDefs;
   error = getChunkDefs(docPath, kSavedCtx, NULL, &oldDefs);
   if (error)
      return error;
   error = getChunkDefs(docPath, notebookCtxId(), NULL, &newDefs);
   if (error)
      return error;

   // ensure we got the arrays we expected
   if (oldDefs.type() != json::ArrayType ||
       newDefs.type() != json::ArrayType)
      return Error(json::errc::ParseError, ERROR_LOCATION);

   cleanChunks(cachePath, oldDefs.get_array(), newDefs.get_array());
   return Success();
}

void onDocRemoved(const std::string& docId, const std::string& docPath)
{
   // always remove the uncommitted cache when the doc is closed; if it's
   // opened again, the committed cache will be used to supply its outputs
   FilePath cacheFolder = chunkCacheFolder(docPath, docId, notebookCtxId());
   Error error = cacheFolder.removeIfExists();
   if (error)
      LOG_ERROR(error);
}

void onDocRenamed(const std::string& oldPath,
                  boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   Error error;
   bool removeOldDir = false;

   // compute cache folders and ignore if we can't safely adjust them
   FilePath oldCacheDir = chunkCacheFolder(oldPath, pDoc->id());
   FilePath newCacheDir = chunkCacheFolder(pDoc->path(), pDoc->id());
   if (!oldCacheDir.exists() || newCacheDir.exists())
      return;

   // if the doc was previously unsaved, we can just move the whole folder
   // to its newly saved location
   if (oldPath.empty())
   {
      error = oldCacheDir.move(newCacheDir);
      if (error)
      {
         // if we can't move the cache to the new location, we'll fall back to
         // copy/remove
         removeOldDir = true;
      }
      else
         return;
   }

   error = oldCacheDir.copyDirectoryRecursive(newCacheDir);
   if (error)
   {
      LOG_ERROR(error);
   }
   else if (removeOldDir)
   {
      // remove old dir if we couldn't move the folder above
      error = oldCacheDir.remove();
      if (error)
         LOG_ERROR(error);
   }
}

void onDocAdded(const std::string& id)
{
   std::string path;
   Error error = source_database::getPath(id, &path);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // ignore empty paths and non-R Markdown files
   if (path.empty())
      return;
   FilePath docPath = module_context::resolveAliasedPath(path);
   if (docPath.extensionLowerCase() != ".rmd")
      return;

   FilePath cachePath = chunkCacheFolder(path, id);

   // clean up incompatible cache versions (as we're about to invalidate them
   // by mutating the document without updating them)
   if (cachePath.exists())
   {
      std::vector<FilePath> versions;
      cachePath.children(&versions);
      BOOST_FOREACH(const FilePath& version, versions)
      {
         if (version.isDirectory() && version.filename() != kCacheVersion)
         {
            error = version.remove();
            if (error)
               LOG_ERROR(error);
         }
      }
   }

   // TODO: consider write times of document, cache, and .Rnb -- are there
   // combinations which would suggest we should overwrite the cache with the
   // contents of the notebook?
}

void onDocSaved(FilePath &path)
{
   Error error;
   // ignore non-R Markdown saves
   if (!path.hasExtensionLowerCase(".rmd"))
      return;

   // find cache folder (bail out if it doesn't exist)
   FilePath cache = chunkCacheFolder(path, "", notebookCtxId());
   if (!cache.exists())
      return;

   FilePath saved = chunkCacheFolder(path, "", kSavedCtx);
   if (saved.exists())
   {
      // tidy up: remove any saved chunks that no longer exist
      error = removeStaleSavedChunks(path, saved);
      if (error)
         LOG_ERROR(error);
   }
   else
   {
      // no saved context yet; ensure we have a place to put it
      saved.ensureDirectory();
   }

   // move all the chunk definitions over to the saved context
   std::vector<FilePath> children;
   error = cache.children(&children);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }
   BOOST_FOREACH(const FilePath source, children)
   {
      // compute the target path
      FilePath target = saved.complete(source.filename());

      if (source.filename() == kNotebookChunkDefFilename)
      {
         // the definitions should be copied (we always want them in both
         // contexts)
         error = target.removeIfExists();
         if (!error)
            error = source.copy(target);
      }
      else if (source.isDirectory())
      {
         // library folders should be merged and then removed, so we don't
         // lose library contents
         if (source.filename() == kChunkLibDir)
         {
            error = mergeLib(source, target);
            if (!error)
               error = source.remove();
         }
         else
         {
            // the chunk output folders should be moved; destroy the old copy
            error = target.removeIfExists();
            if (!error)
               error = source.move(target);
         }
      }
      else
      {
         // nothing besides the chunks.json and chunk folders should be here,
         // so ignore other files/content
         continue;
      }

      if (error)
         LOG_ERROR(error);
   }
}

FilePath unsavedNotebookCache()
{
   return module_context::sessionScratchPath().childPath("unsaved-notebooks");
}

SEXP rs_chunkCacheFolder(SEXP fileSEXP)
{
   std::string file = r::sexp::safeAsString(fileSEXP);
   FilePath cacheFolder = chunkCacheFolder(file, "", kSavedCtx);

   r::sexp::Protect protect;
   return r::sexp::create(cacheFolder.absolutePath(), &protect);
}

} // anonymous namespace

FilePath notebookCacheRoot()
{
   return module_context::sharedScratchPath().childPath("notebooks");
}

FilePath chunkCacheFolder(const FilePath& path, const std::string& docId,
      const std::string& nbCtxId)
{
   FilePath folder;
   std::string stem;

   if (path.empty())
   {
      // the doc hasn't been saved, so keep its chunk output in the scratch
      // path
      folder = unsavedNotebookCache().childPath(docId)
                                     .childPath(kCacheVersion);
   }
   else
   {
      std::string id;
      Error error = notebookPathToId(path, &id);
      if (error)
         LOG_ERROR(error);

      folder = notebookCacheRoot().childPath(id + "-" + path.stem())
                                  .childPath(kCacheVersion)
                                  .childPath(nbCtxId);
   }

   return folder;
}

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId,
      const std::string& nbCtxId)
{
   return chunkCacheFolder(
         docPath.empty() ? FilePath() :
                           module_context::resolveAliasedPath(docPath),
         docId, nbCtxId);
}

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId)
{
   return chunkCacheFolder(docPath, docId, notebookCtxId());
}

Error initCache()
{
   source_database::events().onDocRenamed.connect(onDocRenamed);
   source_database::events().onDocRemoved.connect(onDocRemoved);
   source_database::events().onDocAdded.connect(onDocAdded);

   module_context::events().onSourceEditorFileSaved.connect(onDocSaved);

   RS_REGISTER_CALL_METHOD(rs_chunkCacheFolder, 1);

   module_context::scheduleDelayedWork(boost::posix_time::seconds(30),
      cleanUnusedCaches, true);

   return Success();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<commit_msg>pass path to notebook save listener by value<commit_after>/*
 * NotebookCache.cpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "SessionRmdNotebook.hpp"
#include "SessionRnbParser.hpp"
#include "NotebookCache.hpp"
#include "NotebookChunkDefs.hpp"
#include "NotebookPaths.hpp"
#include "NotebookOutput.hpp"
#include "NotebookHtmlWidgets.hpp"

#include <boost/foreach.hpp>

#include <session/SessionUserSettings.hpp>
#include <session/SessionModuleContext.hpp>
#include <session/SessionSourceDatabase.hpp>

#include <core/Algorithm.hpp>

#include <r/RExec.hpp>
#include <r/RRoutines.hpp>

// The version identifier for the cache format. Changing this invalidates old
// caches, and should be done only when making breaking changes to the
// cache format.
#define kCacheVersion "1"

#define kCacheAgeThresholdMs 1000 * 60 * 60 * 24 * 2

using namespace rstudio::core;

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {
namespace {

// it's much faster to load a notebook from its cache than it is to rehydrate
// it from its .Rnb, so we keep it around even if the document is closed (as
// it's somewhat common to open and close a document periodically over the
// course of working on a project, and it's nice when it opens quickly).
//
// however, we don't want to keep the cache around *forever* just in case we
// might need it, as it can be quite large. as a compromise, an unused cache
// hangs around for a couple of days, then gets automatically swept up by this
// function.
void cleanUnusedCaches()
{
   FilePath cacheRoot = notebookCacheRoot();
   if (!cacheRoot.exists())
      return;

   std::vector<FilePath> caches;
   Error error = cacheRoot.children(&caches);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   std::string nbCtxId = notebookCtxId();
   BOOST_FOREACH(const FilePath cache, caches)
   {
      // make sure this looks like a notebook cache
      if (!cache.isDirectory())
         continue;
      std::vector<std::string> parts = core::algorithm::split(
            cache.stem(), "-");
      if (parts.size() < 2)
         continue;

      // get the path of the notebook associated with the cache
      FilePath path;
      error = notebookIdToPath(parts[0], &path);
      if (error)
      {
         if (error.code() == boost::system::errc::no_such_file_or_directory)
         {
            // we have no idea what notebook this cache is for, so it's
            // unusable; delete it
            error = cache.remove();
            if (error)
               LOG_ERROR(error);
         }
         else
         {
            LOG_ERROR(error);
         }

         continue;
      }

      // is this document still open? if so, leave the cache alone.
      std::string id;
      source_database::getId(module_context::createAliasedPath(
               FileInfo(path)), &id);
      if (!id.empty())
      {
         continue;
      }

      std::vector<FilePath> contexts;
      error = cache.complete(kCacheVersion).children(&contexts);
      if (error)
      {
         LOG_ERROR(error);
         continue;
      }

      BOOST_FOREACH(const FilePath context, contexts)
      {
         // skip if not our context or the saved context
         if (context.filename() != kSavedCtx &&
             context.filename() != nbCtxId)
            continue;

         // check the write time on the chunk defs file (updated when the doc is
         // mutated or saved)
         FilePath chunkDefs = context.complete(kNotebookChunkDefFilename);
         if (!chunkDefs.exists())
            continue;
         if ((std::time(NULL) - chunkDefs.lastWriteTime()) > kCacheAgeThresholdMs)
         {
            // the cache is old and the document hasn't been opened in a while --
            // remove it.
            error = context.remove();
            if (error)
               LOG_ERROR(error);
         }
      }
   }
}

Error removeStaleSavedChunks(FilePath& docPath, FilePath& cachePath)
{
   Error error;
   if (!cachePath.exists())
      return Success();

   // extract the set of chunk IDs from the definition files
   json::Value oldDefs;
   json::Value newDefs;
   error = getChunkDefs(docPath, kSavedCtx, NULL, &oldDefs);
   if (error)
      return error;
   error = getChunkDefs(docPath, notebookCtxId(), NULL, &newDefs);
   if (error)
      return error;

   // ensure we got the arrays we expected
   if (oldDefs.type() != json::ArrayType ||
       newDefs.type() != json::ArrayType)
      return Error(json::errc::ParseError, ERROR_LOCATION);

   cleanChunks(cachePath, oldDefs.get_array(), newDefs.get_array());
   return Success();
}

void onDocRemoved(const std::string& docId, const std::string& docPath)
{
   // always remove the uncommitted cache when the doc is closed; if it's
   // opened again, the committed cache will be used to supply its outputs
   FilePath cacheFolder = chunkCacheFolder(docPath, docId, notebookCtxId());
   Error error = cacheFolder.removeIfExists();
   if (error)
      LOG_ERROR(error);
}

void onDocRenamed(const std::string& oldPath,
                  boost::shared_ptr<source_database::SourceDocument> pDoc)
{
   Error error;
   bool removeOldDir = false;

   // compute cache folders and ignore if we can't safely adjust them
   FilePath oldCacheDir = chunkCacheFolder(oldPath, pDoc->id());
   FilePath newCacheDir = chunkCacheFolder(pDoc->path(), pDoc->id());
   if (!oldCacheDir.exists() || newCacheDir.exists())
      return;

   // if the doc was previously unsaved, we can just move the whole folder
   // to its newly saved location
   if (oldPath.empty())
   {
      error = oldCacheDir.move(newCacheDir);
      if (error)
      {
         // if we can't move the cache to the new location, we'll fall back to
         // copy/remove
         removeOldDir = true;
      }
      else
         return;
   }

   error = oldCacheDir.copyDirectoryRecursive(newCacheDir);
   if (error)
   {
      LOG_ERROR(error);
   }
   else if (removeOldDir)
   {
      // remove old dir if we couldn't move the folder above
      error = oldCacheDir.remove();
      if (error)
         LOG_ERROR(error);
   }
}

void onDocAdded(const std::string& id)
{
   std::string path;
   Error error = source_database::getPath(id, &path);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }

   // ignore empty paths and non-R Markdown files
   if (path.empty())
      return;
   FilePath docPath = module_context::resolveAliasedPath(path);
   if (docPath.extensionLowerCase() != ".rmd")
      return;

   FilePath cachePath = chunkCacheFolder(path, id);

   // clean up incompatible cache versions (as we're about to invalidate them
   // by mutating the document without updating them)
   if (cachePath.exists())
   {
      std::vector<FilePath> versions;
      cachePath.children(&versions);
      BOOST_FOREACH(const FilePath& version, versions)
      {
         if (version.isDirectory() && version.filename() != kCacheVersion)
         {
            error = version.remove();
            if (error)
               LOG_ERROR(error);
         }
      }
   }

   // TODO: consider write times of document, cache, and .Rnb -- are there
   // combinations which would suggest we should overwrite the cache with the
   // contents of the notebook?
}

void onDocSaved(FilePath path)
{
   Error error;
   // ignore non-R Markdown saves
   if (!path.hasExtensionLowerCase(".rmd"))
      return;

   // find cache folder (bail out if it doesn't exist)
   FilePath cache = chunkCacheFolder(path, "", notebookCtxId());
   if (!cache.exists())
      return;

   FilePath saved = chunkCacheFolder(path, "", kSavedCtx);
   if (saved.exists())
   {
      // tidy up: remove any saved chunks that no longer exist
      error = removeStaleSavedChunks(path, saved);
      if (error)
         LOG_ERROR(error);
   }
   else
   {
      // no saved context yet; ensure we have a place to put it
      saved.ensureDirectory();
   }

   // move all the chunk definitions over to the saved context
   std::vector<FilePath> children;
   error = cache.children(&children);
   if (error)
   {
      LOG_ERROR(error);
      return;
   }
   BOOST_FOREACH(const FilePath source, children)
   {
      // compute the target path
      FilePath target = saved.complete(source.filename());

      if (source.filename() == kNotebookChunkDefFilename)
      {
         // the definitions should be copied (we always want them in both
         // contexts)
         error = target.removeIfExists();
         if (!error)
            error = source.copy(target);
      }
      else if (source.isDirectory())
      {
         // library folders should be merged and then removed, so we don't
         // lose library contents
         if (source.filename() == kChunkLibDir)
         {
            error = mergeLib(source, target);
            if (!error)
               error = source.remove();
         }
         else
         {
            // the chunk output folders should be moved; destroy the old copy
            error = target.removeIfExists();
            if (!error)
               error = source.move(target);
         }
      }
      else
      {
         // nothing besides the chunks.json and chunk folders should be here,
         // so ignore other files/content
         continue;
      }

      if (error)
         LOG_ERROR(error);
   }
}

FilePath unsavedNotebookCache()
{
   return module_context::sessionScratchPath().childPath("unsaved-notebooks");
}

SEXP rs_chunkCacheFolder(SEXP fileSEXP)
{
   std::string file = r::sexp::safeAsString(fileSEXP);
   FilePath cacheFolder = chunkCacheFolder(file, "", kSavedCtx);

   r::sexp::Protect protect;
   return r::sexp::create(cacheFolder.absolutePath(), &protect);
}

} // anonymous namespace

FilePath notebookCacheRoot()
{
   return module_context::sharedScratchPath().childPath("notebooks");
}

FilePath chunkCacheFolder(const FilePath& path, const std::string& docId,
      const std::string& nbCtxId)
{
   FilePath folder;
   std::string stem;

   if (path.empty())
   {
      // the doc hasn't been saved, so keep its chunk output in the scratch
      // path
      folder = unsavedNotebookCache().childPath(docId)
                                     .childPath(kCacheVersion);
   }
   else
   {
      std::string id;
      Error error = notebookPathToId(path, &id);
      if (error)
         LOG_ERROR(error);

      folder = notebookCacheRoot().childPath(id + "-" + path.stem())
                                  .childPath(kCacheVersion)
                                  .childPath(nbCtxId);
   }

   return folder;
}

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId,
      const std::string& nbCtxId)
{
   return chunkCacheFolder(
         docPath.empty() ? FilePath() :
                           module_context::resolveAliasedPath(docPath),
         docId, nbCtxId);
}

FilePath chunkCacheFolder(const std::string& docPath, const std::string& docId)
{
   return chunkCacheFolder(docPath, docId, notebookCtxId());
}

Error initCache()
{
   source_database::events().onDocRenamed.connect(onDocRenamed);
   source_database::events().onDocRemoved.connect(onDocRemoved);
   source_database::events().onDocAdded.connect(onDocAdded);

   module_context::events().onSourceEditorFileSaved.connect(onDocSaved);

   RS_REGISTER_CALL_METHOD(rs_chunkCacheFolder, 1);

   module_context::scheduleDelayedWork(boost::posix_time::seconds(30),
      cleanUnusedCaches, true);

   return Success();
}

} // namespace notebook
} // namespace rmarkdown
} // namespace modules
} // namespace session
} // namespace rstudio

<|endoftext|>