読者です 読者をやめる 読者になる 読者になる

dlopenやdlsym辺りの実装を読んでそのうちまとめたい

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
  FILE *fp;
  if ((fp = fopen("hello.c", "w")) == NULL) {
    fprintf(stderr, "file cannot open");
    exit(EXIT_FAILURE);
  }
  fprintf(fp,
    "#include <stdio.h>\n"
    "void hello(void) { printf(\"hello dl world!\\n\"); }\n"
  );
  fclose(fp);

  system("gcc -shared hello.c -o hello.so");
  
  void *dl = dlopen("./hello.so", RTLD_LAZY);
  if (dl == NULL) {
    fprintf(stderr, "dl cannot open");
    exit(EXIT_FAILURE);
  }

  void (*f)(void) = dlsym(dl, "hello");
  if (f == NULL) {
    fprintf(stderr, "dl cannot open");
    exit(EXIT_FAILURE);
  }

  f();  // hello dl world!
  dlclose(dl);

  return 0;
}

大量のメモリを使用するプログラムからコマンドを実行する方法というのを読んだ

メモリを多く使用したプロセスから繰り返しfork()する場合,performance issuesになりうるという話.

StackOverflow linux - 大量のメモリを使用するプログラムからコマンドを実行する方法 - スタック・オーバーフロー

実際困ることあるらしく

...

結論としてはposix_spawn()使えというのが良いそうだ.

リンクされているvforkの話も面白かった. http://www.a-k-r.org/d/2014-09.html#a2014_09_06

vfork速いけどメモリ空間をコピーしない特性上クセはある.子プロセスがデッドロックするのでマルチスレッドでforkしたら直後にexecしろというのと同様,vforkしたら直後にexecするべきなのだろう.(しない有用な例はあまり思いつかないけれど)

UNIX上でのC++ソフトウェア設計の定石 (3) - memologue

マルチプロセス難しいなー.

github.io

htmlを生成するテンプレートエンジンJade Jade - Template Engine と,cssを生成するStylus Expressive, dynamic, robust CSS — expressive, robust, feature-rich CSS preprocessor の使い方について少し勉強したので,かねてより手を付けたいと思っていたgithub.ioにとりあえずindexページを置いた.置いてみて思ったけれど,こことの使い分けのビジョンがイマイチ沸かないし不要そうだ.

http://fimbul.github.io/

Jadeはpythonライクなindentでタグのスコープが決まり,閉じタグを書く必要が無いとか,- var title = "page title"などと変数に値を入れておいて,#{title}で後から参照出来るとか便利なところは結構ある. templateなのでもっと色々使いまわしたり,includeでそのままファイルを埋め込むとか出来るようだけれど読んだだけでそこまで試してない.

Stylusは,sassやlessに似たものだけれど新しいもの好きなので試してみた.変数や条件分岐,ループなど一通り揃っている.

簡単にnpmで全部入るしgulp, gulp-stylus, gulp-jadeも入れて全部gulpを叩けばページが生成されるようにしてみたらよさ気だった.

fimbul.github.io/index.jade at master · fimbul/fimbul.github.io · GitHub

しかし,jadeにコードを埋め込もうと思うと普通にpreタグの中に#include と書くと#がJadeのdirectiveに認識されたりするし, かといって | を使うと</iostream>のような望まぬ閉じタグが生成されたりして結構困った.=を使うとエスケープしてくれるんだけど,今度は= "#include "とダブルクォートで囲ってやる必要があり コードが複数行になるとヒアドキュメントが無いためにいちいち各行を囲い,更に末尾に\nを追加し,途中にダブルクォートがあればバックスラッシュでエスケープしてやらないと上手くいかない.

とりあえずはコードをそのように変換してくれるスクリプトで対処すれば良いけれど,どうすれば幸せになれるんだろう.理解が足りない.

巷で流行りの活動日記

木構造系のデータ構造の実装のベストプラクティスが知りたいと思いつつ,適当に非常に簡単なものを試作するなど.
競プロ用途などで,自分用に簡単なprint機能などを備えた木構造のライブラリなどを作っておきたいという気持ちはある.
TSから標準に入るoptionalを使えば不正値を表現出来るので親が居ないだとか,子が居ないという状態を持つのは楽になる筈.

とりあえず二分木にしたけれど,葉の数nを渡せるような形にしてi番目の子にインデックスアクセス出来る方が良いのかも.

http://melpon.org/wandbox/permlink/FDIoIYYovywpE6ym

#include <functional>
#include <iostream>
#include <memory>
#include <queue>

namespace tree {

struct pre_order_tag {};
static constexpr pre_order_tag pre_order{};

struct in_order_tag {};
static constexpr in_order_tag in_order{};

struct post_order_tag {};
static constexpr post_order_tag post_order{};

struct dfs_order_tag {};
static constexpr dfs_order_tag dfs_order{};

template <typename T>
struct binary_tree : std::enable_shared_from_this<binary_tree<T>> {
  binary_tree(T v,
              std::weak_ptr<binary_tree> p = {},
              std::shared_ptr<binary_tree> l = nullptr,
              std::shared_ptr<binary_tree> r = nullptr)
    : value(v), parent(p), left(l), right(r) {}
  binary_tree(const binary_tree&) = default;
  binary_tree(binary_tree&&) = default;

  std::shared_ptr<binary_tree> append_left(std::shared_ptr<binary_tree> c) {
    left = c;
    c->parent = this->shared_from_this();
    return this->shared_from_this();
  }

  std::shared_ptr<binary_tree> append_right(std::shared_ptr<binary_tree> c) {
    right = c;
    c->parent = this->shared_from_this();
    return this->shared_from_this();
  }

  std::shared_ptr<binary_tree> remove_left() {
    left = nullptr;
    return this->shared_from_this();
  }

  std::shared_ptr<binary_tree> remove_right() {
    right = nullptr;
    return this->shared_from_this();
  }

  T value;
  std::weak_ptr<binary_tree> parent;
  std::shared_ptr<binary_tree> left;
  std::shared_ptr<binary_tree> right;
};

namespace detail {

  template <typename Tag>
  struct print;

  template <>
  struct print<pre_order_tag> {
    template <typename T, typename P>
    static void eval(const T& t, const P& printer) {
       if (t == nullptr) return;
       printer(t);
       eval(t->left, printer);
       eval(t->right, printer);
    }
  };

  template <>
  struct print<in_order_tag> {
    template <typename T, typename P>
    static void eval(const T& t, const P& printer) {
       if (t == nullptr) return;
       eval(t->left, printer);
       printer(t);
       eval(t->right, printer);
    }
  };

  template <>
  struct print<post_order_tag> {
    template <typename T, typename P>
    static void eval(const T& t, const P& printer) {
       if (t == nullptr) return;
       eval(t->left, printer);
       eval(t->right, printer);
       printer(t);
    }
  };

  template <>
  struct print<dfs_order_tag> {
    template <typename T, typename P>
    static void eval(const T& t, const P& printer) {
      if (t == nullptr) return;
      std::queue<T> q;
      q.push(t);
      while (!q.empty()) {
        const auto& tmp = q.front();
        q.pop();
        printer(tmp);
        if (tmp->left != nullptr) q.push(tmp->left);
        if (tmp->right != nullptr) q.push(tmp->right);
      }
    }
  };

}  // namespace detail

struct default_printer_t {
  template <typename T>
  void operator()(const T& t) const { std::cout << t->value << std::endl; }
};

static constexpr default_printer_t default_printer{};

template <typename T, typename Tag = pre_order_tag>
inline void print(const T& t,
           Tag = {}, const std::function<void(const T&)>& printer = default_printer) {
  if (t != nullptr) detail::print<Tag>::eval(t, printer);
}

}  // namespace tree

int main() {
  using tree_type = tree::binary_tree<int>;

  auto t = std::make_shared<tree_type>(0);
  t->append_left(std::make_shared<tree_type>(1));
  t->append_right(std::make_shared<tree_type>(2));
  t->left->append_left(std::make_shared<tree_type>(3));
  t->left->append_right(std::make_shared<tree_type>(4));
  t->right->append_left(std::make_shared<tree_type>(5));
  t->right->append_right(std::make_shared<tree_type>(6));

  std::cout << "pre_order:" << std::endl;
  tree::print(t);
 
  std::cout << "in_order:" << std::endl;
  tree::print(t, tree::in_order);
  
  std::cout << "post_order:" << std::endl;
  tree::print(t, tree::post_order);

  std::cout << "dfs_order:" << std::endl;
  tree::print(t, tree::dfs_order);
}

Tower of Hanoi

#include <iostream>
#include <stack>

int main() {
  int n;
  std::cin >> n;
  std::stack<int> s[3];
  for (int i = n; i > 0; --i) {
    s[0].push(i);
  }

  int mpos = 0;
  while (!s[0].empty() || !s[1].empty()) {
    s[(mpos + 1 + (n % 2)) % 3].push(s[mpos].top());
    s[mpos].pop();
    mpos = (mpos + 1 + (n % 2)) % 3;

    if (s[0].empty() && s[1].empty())
      break;

    if (s[(mpos + 1) % 3].empty()) {
      s[(mpos + 1) % 3].push(s[(mpos + 2) % 3].top());
      s[(mpos + 2) % 3].pop();
    } else if (s[(mpos + 2) % 3].empty()) {
      s[(mpos + 2) % 3].push(s[(mpos + 1) % 3].top());
      s[(mpos + 1) % 3].pop();
    } else if (s[(mpos + 1) % 3].top() < s[(mpos + 2) % 3].top()) {
      s[(mpos + 2) % 3].push(s[(mpos + 1) % 3].top());
      s[(mpos + 1) % 3].pop();
    } else {
      s[(mpos + 1) % 3].push(s[(mpos + 2) % 3].top());
      s[(mpos + 2) % 3].pop();
    }
  }

  std::cout << "----" << std::endl;

  for (int i = 0; i < 3; ++i) {
    while (!s[i].empty()) {
      std::cout << s[i].top() << ' ';
      s[i].pop();
    }
    std::cout << std::endl;
  }
}

lambda is tuple

理解したのでメモ

melpon.org

#include <iostream>

auto stack = [](auto... xs) { 
    return [=](auto access) { 
        return access(xs...);
    }; 
}; 

auto size = [](auto xs) { 
    return xs([=](auto... z) {
        return sizeof...(z);
    }); 
};

auto push = [](auto xs, auto x) {
    return xs([=](auto... z) {
        return [=](auto access) {
            return access(x, z...);
        };
    });
};

auto pop = [](auto xs) {
    return xs([=](auto, auto... z) {
        return [=](auto access) {
            return access(z...);
        };
    });
};

auto top = [](auto xs) {
    return xs([=](auto v, auto...) {
        return v;
    });
};

int main() {
    auto s = push(push(push(stack(), 1), "lambda is tuple"), 3.14);
    std::cout << size(s) << std::endl;
    std::cout << top(s) << ", "
              << top(pop(s)) << ", " 
              << top(pop(pop(s)))
              << std::endl;
}

c++ - Is there a name for this tuple-creation idiom? - Stack Overflow

型リストからindex_sequenceを作る

組込のfolding-exprを再帰深度O(1)とみなすと全体でも再帰深度O(1)

melpon.org

#include <type_traits>
#include <utility>

template<typename... Types>
struct make_indices_from_types {
  private:
    template <std::size_t N, std::size_t...>
    struct make_indices {
        template <std::size_t M, std::size_t... Indices>
        make_indices<N + M, M, Indices...> operator +(const make_indices<M, Indices...>&);
    };
    template <typename> static constexpr int step = 1;
    template <std::size_t... Indices>
    static std::index_sequence<sizeof...(Types) - Indices...> impl(const make_indices<Indices...>&);

  public:
    using type = decltype(impl((make_indices<step<Types>>{} + ...)));
};

int main() {
    static_assert(std::is_same<
                    typename make_indices_from_types<int, char, double, float, void*, bool>::type,
                    std::index_sequence<0, 1, 2, 3, 4, 5>
                  >::value);
}