2016-03-30

C++標準化委員会の文書: P0190R0-P0199R0

[PDF] P0190R0: Proposal for New memory order consume Definition

memory_order_consumeの定義を変更する提案。RCUだけではなくGCなどにも利用できるようにする。Linuxカーネルでも使えるようにする。

[PDF] P0192R0: Adding Fundamental Type for Short Float

32bit以下のサイズのshort float型の追加の提案。

16bit浮動小数点数は機械学習や画像処理の分野で広く使われるようになっている。IEEE 754-2008では2進数16bitのフォーマットが定義されている。今のARMはネイティブにサポートしている。IntelのCPUでもサポートする計画がある。GPUでは、OpenGLが16bit浮動小数点数を規定している。OpenEXRではfloatの半分のサイズの浮動小数点数を組込型同様に扱えるライブラリがある。nVidiaのCUDAでは16bit浮動小数点数行列があるが、C++規格に存在しないために独自規格になっている。GCCはIEEEやARMのサポートのために__fp16型がある。LLVMにもhalf型がある。

16bit浮動小数点数型は現実の需要があるので、C++標準は早急に取り入れるべきであるとする。

型はshort floatで、浮動小数点数リテラルのサフィックスはsもしくはSだ。


short float s1 = 1.0s ;
short float s2 = 1.0S ;

これは早く入るべきだ。

P0193R0: Where is Vectorization in C++‽

C++に手動のベクトル処理を淹れる方法についての考察。ライブラリベースで入れることを検討している。具体的な話はあまりない。

[PDF] P0194R0: Static reflection (revision 4)

静的リフレクション機能の提案。

この提案では、宣言に何らかの演算子を適用すると、メタオブジェクトという型が生成され、その型を用意された特別なtraitsに渡すことで、名前や型などの詳しい情報を得ることができる。

P0195R0: Modernizing using-declarations

using宣言をpack展開に対応させる提案。

例えば、今提案中のoverloadは、

template< typename Head, typename ... Rest >
struct overloader : Head, overload< Rest... >
{
    using Head::operator() ;
    // コンストラクターなど
} ;

template < typename T >
struct overloader< T > : T
{
    using T::operator () ;
} ;

template < typename ... Types >
constexpr auto make_overloader( Types && ... args )
{
    return overloader< Types ... >( std::forward<Types>...) ;
}

のように再帰的に書かなければならない。これは非効率的だ。

再帰的に書かなければならない理由は、using宣言がパック展開に対応していないからだ。対応していれば以下のように書ける。

template < typename ... Types >
struct overloader : Types ...
{
    using Types::operator() ... ;
} ;

確かに便利だが、利用方法は限られる気がする。あって困ることはないだろう。

[PDF] P0196R0: A generic none_t literal type for Nullable types

型none_tとその値noneの提案。

optionalやanyといったライブラリでは、何も値が入っていないnullな状態になり得る(nullable)。各ライブラリごとにnullを表す別々の型を定義して使うのは冗長であるし、使い勝手も悪い。そこで、nullを意味する共通の型を定義しようという提案。これでジェネリックなコードはnullableな型に対してnullが入っているか確認する場合や、nullを入れる場合、単一の型を扱うだけで良くなる。

これも最近流行りのボキャブラリー型だ。入るべきだろう。

[PDF] P0197R0: Default Tuple-like Access

tupleのようなユーザー定義クラスに対して、tupleのようなアクセス(tuple_size, tuple_element, get)を書くのは面倒だ。そういうアクセスはコンパイラーが自動で生成すればいい。この文書は、tupleのようなアクセスをデフォルトで自動で生成する提案だ。

例えば以下のようなクラス、

struct X
{
    char m1 ;
    short m2 ;
    int m3 ;
} ;
X x{ 1, 2, 3 } ;

に対して、以下のようなtuple風アクセスが何もせずとも自動的に生成される。


tuple_size<X>::value ; // 3
tuple_element< 1, X>::type ; // short
get<2>( x ) ; // int型の値3
get<char>(x) ; // char型の値1

public非staticデータメンバーに対するtuple風アクセスが自動生成される。

protected, privated, virtualな基本クラスがない場合、基本クラスも再帰的に探される。

template  < typename Head, typename ... Rest >
struct X : X< Rest ... >
{
    Head m ;
    X( Head && head, Rest && ... rest )
        : X< Rest ... >( std::forward< Rest >( rest ) ... ),
            m( std::forward<Head>(head) )
    { }
} ;

template < typename T >
struct X<T>
{
    T m ;
    X( T && t )
        : m( std::forward<T>(t) )
    { }
} ;

X< char, short, int > x{ 1, 2, 3 } ;

tuple_size<X>::value ; // 3
tuple_element< 1, X>::type ; // short
get<2>( x ) ; // int型の値3
get<char>( x ) ; // char型の値1

いわば簡易的な静的リフレクションで、シリアライゼーションなどの用途に使えるだろう。ちなみに、提案はConcept TSに依存しているが、見た限り、コンパイル時チェックに使っているだけで、Concept TSの依存を取り除くのは可能のようだ。

いまのConcept TSには依存しないでほしい。

[PDF] P0198R0: Default Swap

クラスに対してデフォルトのswapを自動生成する提案。コンパイラーはデフォルトのスワップを生成する。デフォルトのswapはメンバーごとのswapを行う。

struct X
{
    int m1 ;
    std::string m2 ;
    std::array<int, 10> m3 ;
} ;

void f( X & a, X & b)
{
    // メンバーごとの効率的なswapが行われる
    swap( a, b ) ;
}

std::swapはムーブ可能な型に対しては効率良く動くが、std::arrayのような、ムーブをサポートできない型には効率が悪い。std::arrayのようなクラスは、メンバーごとのswapを行うと効率が良い。そのようなコードは単調で機械的に生成できるので、デフォルトで生成する。swapはfriendなフリー関数として扱われる。

この変更の背景には、swapはコピーやムーブと同じぐらい根本的な操作であるという思想がある。

これは入ってほしい。

[PDF] P0199R0: Default Hash

P0029R0では大抵の型を突っ込めるhash_combineが提案されている。これを使えば、クラス保持する状態のうち、比較に関係のある情報を全部突っ込めばハッシュ計算が素人でも簡単に書けるようになる。問題は、そのようなボイラープレートコードを書くのはダルいということだ。

そこで、そのようなボイラープレートコードをデフォルトで生成されるようにする提案。

P0029とともに入ってほしい提案だ。

ドワンゴ広告

今日は夕方から歯医者だったのでさっさと帰宅した。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

WindowsにLinuxサブシステムを載せてUbuntuのユーザースペースが動く未来が来る?

​Microsoft and Canonical partner to bring Ubuntu to Windows 10 | ZDNet

詳しいことは明日発表されるということで、未だに公式の確証はないのだが、MicrosoftとCanonicalが提携してUbuntuをWindowsに持ってくるという話が上がっている。

現在予測されている内容では、これは単にWindows上で動く仮想環境でUbuntu GNU/Linuxを動かすという話ではなく、WindowsにLinux互換サブシステムを実装して、その上でUbuntuのGNU/Linux上で動くユーザースペースをそのまま持ち込むのではないかという憶測が出ている。つまり、aptでパッケージを管理してbashが使えてその他諸々のUbuntuのユーザースペースのCLIツールが全部使えるということだ。

これは、技術的に可能であろうが、Windowsに十分に互換性のあるLinux互換サブシステムを実装するのは不毛なほど金と労力がかかるだろう。

この憶測が正しいとして、どこまで実装するのかも気になる。CLIツールが動く程度だろうか。X.org互換か、あるいはX.orgが動くまで実装するのだろうか。

Linux互換サブシステムを実装する上で一番だるいのはなんだろうかと考えたところ、システムコールではioctlが一番だるいのではないかと思った。/procと/devもサポートしないと大抵のGNU/Linuxユーザースペースのプログラムは動かないので、やはりダルいだろう。

そしてもうひとつ気になるのが、ターミナルエミューレーターだ。まさかcmd.exeではあるまいな。せっかくのGNU/LinuxユーザースペースCLIプログラムが全部動いたとしても、端末がcmd.exeならば全てが台無しだ。

ということを考えると、やはりGNU/Linuxユーザースペースのターミナルエミューレーターも使いたくなり、ということはやはりX.orgが必要になる。

もうひとつの可能性として、Linuxカーネルを使うという手がある。ただ、これはGPLを考えるとありえないように思う。

何にせよ、そこまでしてGNU/Linuxのユーザースペースのツールを使うぐらいなら、最初からGNU/Linuxをネイティブにインストールしたほうがよい。

2016-03-29

C++標準化委員会の文書: P0174R0-P0189R0

P0174R0: Deprecating Vestigial Library Parts in C++17

標準ライブラリの一部をdeprecated扱いとする提案。

以下のライブラリのdeprecated扱いが提案されている。

std::iteratorは基本クラスとして使い、イテレーターの要件を満たすためのネストされた型名をわざわざ手動で定義する手間を省いてくれる。

しかし、本当に手間を省けるかというと疑問だし、クラステンプレートから非修飾名として使うと、依存名ではない問題が発生するので、わかりにくい。たとえば、以下のコードがエラーになる理由は、とてもわかりにくい。

#include <iterator>

template <typename T>
struct MyIterator : std::iterator<std::random_access_iterator_tag, T> {
   value_type data;  // エラー、value_typeが見つからない 
};

maptとmultimapのvalue_compare。

mapとmultimapの実装には使えないし、ユーザーに使われている様子もない。

入力にイテレーターの片方しか取らない版のアルゴリズム(std::mismatchなど)は危険なのでdeprecated扱いにする。

std::allocatorの冗長なメンバー

allocator_traits経由で使うようになったので、冗長なメンバーはdeprecated扱いにする。

文書では、その他の候補としても、いくつかのライブラリを上げている。

vector<bool>は混乱のもとで廃止したいが、ストレージ効率のよい動的に確保されるストレージ上に構築されたビット列コンテナーの代替案が現在はない。

is_literal

is_literalには実用性がない。というのも、ジェネリックなコードで本当に知りたいのは、ある構築が定数初期化であるかどうかであって、型の構築方法の一つがリテラル型になるかどうかなどは実用性がない。

get_temporary_buffer/return_temporary_buffer

もともと不完全なままSTLに残っていたのがそのまま規格にも残ってしまった誰もまともに使っていないライブラリ。

raw storage iterator

今となってはあまり利用価値がない。

無駄な機能は積極的にそぎ落としてほしい。

P0175R0: Synopses for the C library

C++の規格にC言語のライブラリの宣言を追加する提案。今まではヘッダーファイルだけ参照していた。

ユーザーとしては特に変わることはない。

P0177R0: Cleaning up allocator_traits

allocator_traitsのpropagateがイマイチ理解できない理由がわかった。

propagateはアロケーターが状態を持っているかどうかを判別するのに使うのだが、コピー代入とムーブ代入とswapに対して状態があるかどうかを判定するようになっているので、2^3通りの組み合わせがある。当然、ライブラリ側も2^3通りの組み合わせに対処しなければならない。

しかし、現実的に考えれば、アロケーターは状態を持っているかいないかの2通りの場合しかないはずで、原稿の規格はおかしい。これを簡略化するために、既存のpropagate系の判定を全部deprecated扱いにして、単一のpropagateを追加する提案。

これは当然行われるべき変更だ。

P0178R0: Allocators and swap

コンテナーなどのアロケーターを使う型で、アロケーターが状態を持っていて、アロケーターのオブジェクトが等しくない場合、swapが未定義の場合について、それぞれ一時オブジェクトにムーブした上でムーブする方法を使うことで、未定義を回避するフリー関数swapの追加。

P0180R0: Reserve a New Library Namespace Future Standardization

コア言語に新しい機能が入り、ライブラリの設計方法に新しい手法が考案されていき、また現実の需要と事情が変化する中で、近い将来にC++の標準ライブラリには破壊的変更を伴う大幅な変更が必要になるだろう。そのために、新しい名前空間std2とisoを予約する提案。

死蔵されなければよいが。

Ordered By Default

setやmapは、要素の大小比較にoperator <を使っている。これは大抵の場合うまく行くが、世の中には数学的な大小比較を提供していない型も存在する。例えば、。std::complexだ。ただし、complexはsetやmapのための大小比較は提供できる。しかし、そのためには大小比較を定義した上で、比較子をコンテナーに渡してやらなければならない。

struct complex_order
{
    template < typename T >
    bool operator () ( std::complex<T> const & l, std::complex<T> const & r )
    {
        std::tie(l.real, l.img) < std::tie( r.real, r.img ) ;
    }
} ;

int main()
{
    std::set< std::complex<float>, complex_order > s ; 
}

いちいちコンテナに比較子を渡すのが面倒だ。lessを特殊化してやれば明示的に渡す必要はなくなる。

namespace std
{
    template < typename T >
    struct less< std::complex<T> >
    {
        bool operator () ( std::complex<T> const & l, std::complex<T> const & r )
        {
            std::tie(l.real, l.img) < std::tie( r.real, r.img ) ;
        }

    }
} ;

std::set< std::complex<float> > s ;

しかし、これではlessはoperator <を呼び出すものという既存のcontractがこわれてしまう。

そのため、ユーザーにカスタマイゼーションポイントとして、別のテンプレートを提供する。

template <typename T>
struct default_order {
   using type = std::less<T>;
};

template <typename T>
using default_order_t = typename default_order<T>::type;

template < typename Key, typename Compare = default_order_t<Key>,
            typename Allocator = allocator<Key> >
struct set ;

あとは、default_orderを特殊化するだけだ。

template < typename T >
struct default_order< std::complex<T> >
{
    using type = complex_order ;
} ;

この提案は、既存のコードのABI互換性を壊さない。

どんな問題でももう一段階のラッパーをかますことで解決できる。ただし、ラッパーが多すぎるという問題を除いては。

P0184R0: Generalizing the Range-Based For Loop

range-based for loopでイテレーターの先端と終端の型を別にできるように制限を緩和する提案。

Range TSは番兵という概念を導入している。番兵となるイテレーターは別の型でもよい。

struct range
{
    iter begin() const ;
    sentinel end() const ;
}

void f( range const & r )
{

    auto i = r.begin() ;
    auto e = r.end() ;

    for ( ; i != e ; ++i )
    {
        do_somethign( *i ) ;
    }
}

このようなrange型は、現在のrange-based forには渡せない。なぜならば、コード変換のルールが、イテレーターの先頭と終端の型が同じでなければならない制約になっているからだ。この制約をなくし、上のようなrangeをrange-based forに渡せるようにする変更。

適切な変更だ。

P0185R0: Adding [nothrow-]swappable traits (Revision 2)

std::is_swappable<T>, std::is_swappable_with<T, U>, std::is_nothrow_swappable<T>, and std::is_nothrow_swappable_with<T, U>と、その変数テンプレート版(名前が_tで終わるもの)をtype_traitsに追加する提案。

また、utilityにあるswapを、

void swap(optional<T>& rhs)
    noexcept(
        is_nothrow_move_constructible_v<T>
        && noexcept( swap(declval<T&>(), declval<T&>()))
    );

にする。

いい変更だ。

P0186R0: Iterator Facade -

イテレーターを簡単に書けるライブラリの追加。

標準ライブラリに準拠するイテレーターを正しく書くのはボイラープレートコードが多すぎて面倒だ。そこで、このライブラリはC++17とConcept TSとRange TSがあれば簡単にイテレーターが書けるライブラリを提案している。

Concept TSもRange TSもしばらく入らないことを考えると、このライブラリも当分日の目を見ないだろう。

[PDF] P0187R0: Proposal of Bit­field Default Member Initializers

ビットフィールド付きのデータメンバーにデフォルトメンバー初期化しを書けるようにする提案。

struct X
{
    int data : 6 = 42 ;
} ;

文法上の曖昧性を解消してパースを簡単にするために、初期化子には=しか使えない。そして、=の後には初期化子が続かなければならない。例えば{}は書けない。

まあ、いいのではないか。

[PDF] P0188R0: Wording for [[fallthrough]] attribute.

switch文のcaseラベルを通り抜けるのが意図的であると明示的に記述する[[fallthrough]]属性の文面案。

例えば以下のようなコードを書くと、

switch( n )
{
case 2 :
case 3 : // OK、特に何もない
    f() ;
    break ;

case 4 :
    g() ; // 警告、通り抜けてませんか?
case 5 :
    h() ;
}

最近のおせっかいなコンパイラーはcase 4でbreakを書き忘れていないかという警告をしてくる。もし、プログラマーの意図が、nが4の場合は関数gとhを両方呼び出し、nが5の場合は関数hのみ呼び出すというものであれば、上記のコードは正しい。そこで、プログラマーの意図をコード上で伝えるために、[[fallthrough]]を書くことができる。

case 4 : 
    g() ;
    [[fallthrough]]
case 5 :
    h() ;

いちいち書くのが煩わしい以外はいいか。

[PDF] P0189R0: Wording for [[nodiscard]] attribute.

関数の戻り値を使わないと警告される[[nodiscard]]属性の文面案。

// 失敗する可能性があるとても重要な処理
// 失敗した場合はfalseを返す
[[nodiscard]] bool very_important_operation() ;

int main()
{
    // 警告
    very_important_operation() ;
}

また、型に指定した場合、その型を戻り値として使うと、関数に[[nodiscard]]を指定した扱いになる。


[[nodiscard]] struct error_status { } ;
error_status f() ; // [[nodiscard]]がつく

これはC++17に入るコア言語機能の中でも最も一般に役に立つ機能だと思われる。

ドワンゴ広告

ドワンゴではとある一社員が個人的にお菓子神社という霊験あらたかな神社を開いており、参拝者も多い。筆者もポテトチップスという現世利益のために浄賽を投じようと思ったが、ポテトチップスは一袋335kcalもあり、ジョギング換算で5kmに相当し、脂肪換算で46gにあたるため、強い意志力を持ってやめておいた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-24

FBIが2週間でiPhoneをクラックする方法について

FBIがAppleに対してiPhoneをクラックするための特別なOSの開発を要求している裁判において、FBIにほぼ証拠捜査のためにほぼ任意の命令を下せる万能な昔の法律、、All Writs Actそのものの合憲性が問われかねない自体に陥っているため、FBI側も栽培を取り下げたいためか、FBIは2週間でiPhoneをクラックする現実的な方法があるので検証すると発言している。

果たしてそれは何なのか。以下の記事で、その方法が考察されている。

その前に、今回のFBIのiPhoneのクラックというのは、正確に言うと、iPhoneのPasscodeを突破したいというものだ。そのために、正解のパスコードを引き当てるまで入力を繰り返す、いわゆるブルートフォースと呼ばれる愚直な攻撃を実施したいのだが、iPhoneにはパスコードの入力を何度か間違えるとストレージからハッシュ値を削除するという仕組みが存在する。ならばそのストレージをコピーすればいいのではないかと思うだろうが、このストレージというのは、通常のストレージではなく、パスコードを格納するためのチップに内蔵されている極小のストレージのことだ。物理的に簡単にコピーできないように作られている。

My Take on FBI’s “Alternative” Method | Zdziarski's Blog of Things

さて、この記事では、FBIが主張する方法について考察しているが、その前に、FBIが取らないであろう方法が列挙されている。

マイクロプロセッサーを破壊すると、Appleですら修理できないであろうから、そのような方法は取らないだろう。また、脆弱性を利用するものは、おそらく検証に2週間以上かかるから違うだろう。監視カメラの映像を洗って容疑者がパスコードを入力しているところを見つけ出すというのも違うはずだ。というのも、FBIは主張する方法が実際に動くかどうか確証がなく、検証すると言っているからだ。

ではどうするのかというと、NANDミラーリングという方法を使うのではないかと推測している。

NANDミラーリングとは、まずパスコードのハッシュ値を記録している極小のストレージを基板から取り外し、コピーして、再び戻し、パスコードのブルートフォースをする。数回の試行で失敗してストレージが消されたら、コピーしたバックアップを戻して再び試行を再開する。

そんな極小のストレージを基板から剥がしてコピーして差し戻すのはにわかに信じがたい。

npmからkikとその他諸々が消されたまとめ

npmとは、node.jsにおけるパッケージシステムのことだ。npmを使えば、他人の書いたnode.jsベースのプログラムとライブラリの入手と利用がとても簡単になる。

そのnpm界隈が混乱している。発端は以下のURLだ。

I’ve Just Liberated My Modules — Medium

Azer Koçuluはkikという名前のnpmパッケージを公開していた。このkikというソフトウェアの中身についてはここでは関係がない。

さて、それとは別に、kik.comというスマフォ用のチャットアプリを出しているKik Interactive社がいて、kikという名前のパッケージをnpmで出したいので、名前を明け渡すように要求した。

Azerはこの要求を拒否した。すると、Kik Interactive社はnpmの管理者に片っ端からメールを投げまくり、そのうちの一人が反応して、Azerの意思に反して、何の法的根拠もなくパッケージを消した。

Azerはこの行動に対し、npmはもはや信頼できないとし、npmに出していたすべてのパッケージを削除した。

そして阿鼻叫喚の世界に突入する。Azerは様々なCLIツールやライブラリをnpmで公開していた。中でも影響力のあったAzerのパッケージは、left-padだ。

azer/left-pad: String left pad

left-padとは、文字列の左側(先頭)を指定した文字数になるように、指定した文字か指定されない場合は空白文字でパディング(埋める)だけの処理を行う簡単なJavaScriptで書かれたleftpadという名前のライブラリだ。空行を抜けば、10行ぐらいしかない簡単なコードだ。

このコードは有名なnpmパッケージで使われていたらしく、間接的に様々なnpmパッケージが依存していたため、世界中で大混乱を引き起こすことになった。

傑作なのは、当のKik Interactive社すらleft-padに依存していたということだ。Kik Interactive社は今回の件について、メールをすべて公開している。

A discussion about the breaking of the Internet — Medium

Kik社はパッケージ取り下げの理由を、ユーザーの混乱を招くためとしているが、すでに公開されたパッケージの中身が変わる方が混乱を招くし、名前だけ見て中身を確認せずにパッケージを使うバカは混乱して当然だ。

npm運営は、これについて議論しているフォーラムを建設的ではないとして閉じるなど、その後の対応も疑問がある。

今回の件について、興味深い指摘がある。

NPM & left-pad: Have We Forgotten How To Program? | Haney Codes .NET

そもそも、leftpadの中身は10行程度のコードである。空行を抜けば、以下の通り。

module.exports = leftpad;
function leftpad (str, len, ch) {
  str = String(str);
  var i = -1;
  if (!ch && ch !== 0) ch = ' ';
  len = len - str.length;
  while (++i < len) {
    str = ch + str;
  }
  return str;
}

実に多くのパッケージが、このleftpadに依存している。しかし、この程度の関数は数分で書けるのだから、なんでわざわざ依存するんだ?

もっと憂うべきパッケージがある。isArrayだ。このパッケージは一日88万回もダウンロードされていて、2016年2月だけの一ヶ月間に1800万回もダウンロードされていて、72個ものNPMパッケージが依存している。

isarray

isArrayの中身はこうだ。

var toString = {}.toString;

module.exports = Array.isArray || function (arr) {
  return toString.call(arr) == '[object Array]';
};

結局、このコードは本質的にたった一行のコードである。

その他、is-positive-integerという整数が正の整数かどうか判定するパッケージがあるが、これも本質的には4行のコードである。ところが、このパッケージは昨日まで3個もの依存を持っていた(今は0個になっている)

なぜこんなにも多数のパッケージに依存をするのだ?

leftpad, isArray, isPositiveInteger程度、ググる時間を含めても5分程度で書けるはずである。書けない奴はそもそもコードが書けないと言っていい。NPM界隈の人間はコードが書けないのか?

今回の騒動で、以下のような面白いネタパッケージシステムが開発されている。

require-from-twitter

曰く、「Twitterには編集ボタンがないので、最適なJavaScriptモジュールをホストである」

このパッケージシステムを使うには、まずソースコードを自分でツイートして

https://twitter.com/rauchg/status/712799807073419264

しかる後に使う。


const leftPad = await requireFromTwitter('712799807073419264');
console.log(leftPad(1, 5));      // '00001'
console.log(leftPad(1234, 5));   // '01234'
console.log(leftPad(12345, 5));  // '12345'

Twitter社さえ信用すればよい。

ドワンゴ広告

ドワンゴの採用面接を受けると日本Node.jsユーザーグループの「元」代表の@mesoとお話ができるそうだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-18

C++標準化委員会の文書: P0142R0-P0167R1

[PDF] P0142R0: A Module System for C++ (Revision 4)

[PDF] P0143R0: Wording for Modules

[PDF] P0143R1: Wording for Modules

モジュールの提案と文面案。

残念なことに、モジュールはC++17では見送られることが確定した。

[PDF] P0144R1 Structured Bindings

多値から変数宣言と初期化を同時にする文法の提案。

現状では、多値を返す関数の宣言と、多値を返すことは簡単に書ける。

std::tuple< int, double, std::string > f()
{
    return { 1, 2.3, "4" } ;
}

このような関数から、それぞれの型の変数をそれぞれ初期化するのは面倒だ。std::tieを使っても、変数をあらかじめ宣言する必要がある。

int x ;
double y ;
std::string z ;

std::tie( x, y, z ) = f() ;

そこで、以下のような文法で、それぞれの型と値で変数を宣言初期化する機能を提案している。


auto { x, y, z } = f() ;

初期化子としては、std::get<N>をサポートする型(tupleとpair)の他、非staticデータメンバーがすべてpublicなクラス型もサポートされる。また、配列もサポートされていて、それぞれの要素で初期化される。

struct XYZ
{
    int x ;
    double y ;
    std::string z ;
} ;

XYZ f() { return { 1, 2.3, "4" } ; }

auto { x, y, z } = f() ;

int abc[3] = { 1, 2, 3 } ;
auto { a, b, c } = abc ;

これは便利なので入ってほしい。

[PDf] P0145R1: Refining Expression Evaluation Order for Idiomatic C++ (Revision 2)

式の評価順序を固定する提案。

f( a, b, c )という式があったときに、f, a, b, cの式がどの順番で評価されるかは未規定である。例えば、以下のコードの出力結果は未規定である。

void f( int a, int b, int c )
{
    std::cout << a << b << c ;
}

int main()
{
    int i = 0 ;
    f( ++i, ++i, ++i ) ;
}

提案では、ほとんどの式の評価順序を定めているが、唯一、関数の実引数の評価順序は定めていない。そのため、上のコードの出力だけはこの提案でもいまだに未規定である。ただし、f(a)は実引数aより呼び出し可能な式fが先に評価されることが保証されている。

関数の実引数の評価順序が未規定に戻ってしまったのは残念だ。

P0146R1: Regular Void (Revision 1)

void型を完全形にする提案。すなわち、void型のオブジェクトが作れる。

void v1 ;
void v2 = v1 ;
bool b = v1 == v2 ;
void vs[10] ;
auto vp = std::make_unique() ;

テンプレートパラメーターにvoid型を渡した時に例外的に特殊化して対応しなければならない問題が、void型を完全型にするだけで解決する。

[PDF] P0149R0: Generalised member pointers

メンバーポインターの型変換の制限を緩和する提案。

本当に需要がある変換なのだろうか。

[PDF] P0161R0: Bitset Iterators, Masks, and Container Operations

bitsetに2種類のイテレーターを追加する提案。iteratorとindex_iteratorが追加される。

iteratorのoperator *は、イテレーターの指す場所のビットのみがたったbitsetを返す。

std::bitset<3> b{0b110} ;
auto i = b.begin() ;

auto b0 = *i ; // bitset<3>{0b000}
auto b1 = *++i ; // bitset<3>{0b010}
auto b2 = *++i ; // bitset<3>{0b100}

index_iteratorは、イテレーターの指す場所をsize_tで返す。

std::bitset<3> b{0} ;

auto i = b.ibegin() ;
auto i0 = *i ; // 0
auto i1 = *++i ; // 1
auto i2 = *++i ; // 2

既存のコンテナーのイテレーターとは全く違うのでわかりにくい。iteratorは改名すべきだろう。

P0165R1: C++ Standard Library Issues to be moved in Jacksonville

Jacksonville会議で採用が決まった標準ライブラリの問題点の解決案。

P0165R1: Core Language Working Group "ready" Issues for the February, 2016 (Jacksonville) meeting

Jacksonville会議で採用が決まったコア言語の問題点の解決案。

ドワンゴ広告

もうすぐC++17のドラフトが本格的に固まってくるのだが、C++17の新機能として紹介できるわかりやすい大きなコア言語の変更があまりない。どれも小粒な変更ばかりだ。ライブラリはいくつか新しい物が入っているのだが。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-17

Twitterでつぶやかれている絵文字のリアルタイムなトラッカー

emojitracker: realtime emoji use on twitter

Twitterでつぶやかれている絵文字のリアルタイムなトラッカーがある。

このサービスは近々、Twitterの歴史的に認められていた上限なしAPIアクセスの廃止に伴い、終わる見込みだそうだ。

U+1F647 PERSON BOWING DEEPLY 🙇 — Medium

面白いし参考になるので、今のうちに眺めておこう。

ちなみに、この絵文字トラッカーはユニコードコンソーシアムにおいて絵文字の実際の利用需要の参考に引用されたこともある。

Twitterがまだおおらかな頃、このような面白いサービスを作るために、APIへの上限なしアクセス権を気軽にホイホイ発行していたのだが、Twitterからのメールでの連絡で、近々そのような上限なしアクセスを廃止するので、商用アクセスAPIであるGnipに移行するか諦めろという言われたと報告している。残念なことだ。

Hacker NewsではTwitter社員だと自称する人間が今回の決定について適切な利用法であれば例外的措置もあり交渉も可能であり、我々に交渉もせずに公にしたのは残念であると言い訳がましいことを書き込んでいるが、公開されたメールの文面をみれば、商用APIに移行するか諦めろという最終通告にしか読めないが、公開されているメールの文面は間違っているのか? いかにも言い訳がましいと反論されている。

2016-03-16

C++標準化委員会の文書: P0119R1-P0138R1

今回から、個人的な感想も意図的に書いてみることにした。

[PDF] P0119R1: Overload sets as function arguments

オーバーロードされた関数の名前からlambda式を暗黙に生成する機能の提案。

オーバーロードされた関数名は、関数の集合を表すので、テンプレート実引数に渡すことはできない。

void f( int ) ;
void f( double ) ;

template < typename Func >
void g( Func func ) ;

int main()
{
    // エラー
    // どのfか曖昧
    g( f ) ;
}

これは、lambda式を経由すれば渡すことができる。

g( []( auto && x ) -> decltype(auto) { return f( x ) ; } ) ;

しかし、こんな自明なlambda式をわざわざ書くのは面倒だ。そこで、関数のオーバーロードのセットを指すid-expressionが実引数として指定されたら、このようなlambda式を生成するテンプレートの実引数推定を追加する提案。

テンプレートの実引数推定にルールを追加するので、autoで受けることもできる。

auto less = (<) ;
less( a, b ) ;

確かに便利だが、どの程度の需要があるだろうか。

[PDF] span: bounds-safe views of objects for sequences

連続したストレージとそのサイズを管理して配列のようにアクセスできるライブラリspanの提案。

もともとは、多次元配列としても使えるarray_viewの提案だったが、多次元配列サポートをなくし、また名前も変えてspanとした。Guidelines Support Libraryのspanを

spanは、連続したストレージとその長さを管理できる。つまり、ポインターとその長さを管理するためのクラスだ。

最近のC++の標準ライブラリには、このような"vocabulary type"の提案が多い。vocabulary typeはコードを読みやすくする。

spanはコンパイル時の配列の長さ指定と、実行時の配列の長さ指定の両方をサポートする。

int a[10] ;
// コンパイル時に長さを指定した固定長span
span<int, 10> s1{ a } ; 
// 実行時に長さを指定した動的長さspan
span<int> s2{ a, 10 } ;

spanを経由した配列へのアクセスには範囲チェックが行われる、範囲外アクセスは未定義の動作を引き起こす。固定長と動的長さspanは相互に代入可能だが、長さのチェックはもちろん行われる。

実際の使い方は、arrayとほぼ同じだ。

興味深いのは、P0257の提案されているbyteを使って、standard layout型Tのspan<T>をspan<byte>に変換することで、内部表現を読み書きすることをサポートしている点だ。キャストを手で書かずに済む。

このライブラリは便利なのでほしい。

[PDF] P0123R1: string_span: bounds-safe views for sequences of characters

string_viewがstring_spanに改名された。文字列を共通の方法で操作できるラッパーライブラリ。

string_viewの方がわかりやすい気がするが自転車小屋について議論しても仕方がないのだろうか。

P0124R1: Linux-Kernel Memory Model

Linuxカーネルのメモリモデルについて不文律であるところも含めて完全に解説する文書。

背景として、Linusにatomic操作ライブラリは使い物にならんと言われたので、まずLinuxカーネルにおけるメモリモデルを理解するところから始めるそうだ。

[PDF] P0126R1: std::synchronic<T>

リソースを浪費せずに、あるオブジェクトの値が期待する値になるまで待つライブラリ、std::synchronic<T>の提案

使い方は極めて原始的なcondition variableに近い。

P0128R1: constexpr if

コンパイル時条件分岐constexpr ifの提案。

前回からの変更点は、一つの新しいキーワードconstexpr_ifから、既存のキーワードを連続したconstexpr ifになったこと。

template < typename T, typename ... Rest >
void f(T && t, Rest && ... rest )
{
    constexpr if ( sizeof...(rest) )
    {
        // tを処理
        // 引数ゼロ個のfのオーバーロードは必要ない。
        f( std::forward<Rest>(rest)... ) ;
    }
}

constexpr elseもある。

constexpr if ( ... )
{

}
constexpr else
{

}

どういう形であれ、コンパイル時条件分岐はほしい。

[PDF] P0138R1: Construction Rules for enum class Values

enumを強いtypedefの代わりに使える機能の提案。

内部型が指定されていて、enumeratorの存在しないenumは、縮小変換のないリスト初期化を使えば、キャストを使わずに初期化できるようにする提案。

enum class E : int { } ;

E e{123} ;

void f( E e ) ;

void g()
{
    f( { 123 } ) ;
}

キャストが必要なくなるのは初期化だけなので、これでは使い方が煩わしいことに変わりはない。本物の強いtypedefの方がいい。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-10

ファミコンのゲームを3次元化するエミュレーターがすごい

ファミコン画面立体化エミュレータ「3DNES」ベータ版公開。思い出のゲームをリアルタイムに3D変換してプレイ - Engadget Japanese

ファミコンの画像を立体的にして遊べるファミコンエミュレーターが公開されたそうだ。

これはとても面白いコンセプトだ。

金と労力をかけて、特定のゲームに特化したエミュレーターを作れば、もっと精度は良くなるはずで、すでにファミコンエミュレーターはWiiUや3DSでVCという商業的な流通経路もあるので、将来的には公式にこのようなエミュレーターを出すのはあり得る未来だ。

もちろん、一から作るという手もあるが、そのような再実装よりも商業的価値が高いはずだ。

2016-03-07

C++標準化委員会の文書のレビュー: P0063R1-P0096R1

P0063R1: C++17 should refer to C11 instead of C99

C++規格が参照するC言語規格をC99からC11にする変更。

C11の変更がC++とかち合う部分や、C++とCの文面を厳密に解釈した際の奇妙な結果が考察されていて面白い。t

P0067R1: Elementary string conversions, revision 1

整数と浮動小数点数を文字列と相互変換するライブラリの提案。

このライブラリはロケールのように実行時にフォーマットを切り替える機能がなく、かつ、動的メモリ確保も行わない。

用途は、国際化対応が必須ではないパフォーマンスが重要なテキストベースフォーマットのパース。例えば、JSONやXMLなど。

[PDF] P0072R1: Light-Weight Execution Agents

スレッドより制約がある実行単位(SIMDやGPGPUなど)を、実行媒体(execution agent)として扱うための定義を文面に追加する提案。

[PDF] P0073R1: On unifying the coroutines and resumable functions proposals

コルーチンとレジューム可能関数の統一に向けて。

[PDF] P0075R1: Template Library for Parallel For Loops

インデックスベースの並列forループアルゴリズムを追加する提案。

std::for_loop( std::seq, 0, n, [&]( auto i ){ A[i] = B[i] ;} ) ;

これは、以下と同じ意味だ。

for ( unsigned i = 0 ; i != n ; ++i )
    A[i] = B[i] ;

seqをparにすれば、並列実行版になる。

アルゴリズムには、通常のレンジ版と、カウント版がある。レンジ版は、開始インデックスと終了インデックスを取り、イテレーター風にHalf Open Rangeとして終了インデックスに到達するまでインデックスをすすめる。カウント版は、開始インデックスとイテレート回数を取る。インデックスは指定された回数だけ進められる。カウント版のアルゴリズムは、末尾が"_n"という名前になっている。

std::for_loop_n( i, n, f ) ;

は、

for ( unsigned count = 0 ; count != n ; ++count )
    f( ++i ) ;

のような意味になる。

またこの提案はstride版のアルゴリズムも提供する。これは末尾が"_strided"となっている。stride版はインデックスの刻み幅を指定できる。

std::for_loop_strided( i, n, m, f ) ;

は、

for ( auto I = i ; I != n ; I += m )
    f( I ) ;

のような意味になる。

Reductionのサポート。Reductionとは、ロックを使わずに一つの変数を並列に変更でき、最終的な値はシリアルに実行した場合と同じものを得る方法である。その仕組みは、並列実行には変数のviewを見せておき、複数のviewから最終的な値を計算する方法を提供することによって実現している。

float f(int n, float x[]]) {
    float s = 0;
    for_loop(par, 0, n, reduction(s,0.0f,std::plus<float>()),
        [&](int i, float& s_) {
            s_ += x[i] ;
        });
    return s;
}

この例では、変数sの最終的な値は、途中の変更をすべて加算することで得られるので、そのようなreductionを与えている。for_loopの最後の実引数は、Variable Templatesになっていて、reductionをいくつでも受け取ることができる。パラーメーターパックの最後が呼び出し可能な関数オブジェクトとなる。reductionを使った数だけ、関数オブジェクトの呼び出しに実引数が追加される。

inductionのサポート。inductionはループのイテレート回数に応じて線形に増える値である。そのような値をユーザーが手で計算すると間違いの元なので、ライブラリが用意されている。


float* zipper(int n, float* x, float *y, float *z) {
    for_loop(par, 0, n,
        induction(x),
        induction(y),
        induction(z,2),
        [&](int i, float* x_, float* y_, float* z_) {
            *z_++ = *x_++;
            *z_++ = *y_++;
        });
    return z;
}

inductionもreductionと同じく、いくつでも使える。使った数だけ実引数に渡される。上記のコードは、以下のコードと同じ意味である。


float* zipper(int n, float* x, float *y, float *z) {
    for_loop(par, 0, n,
        [&](int i) {
            *(z+i*2)++ = *(x+i)++;
            *(z+i*2)++ = *(y+i)++;
        });
    return z;
}

[PDF] P0076R1: Vector and Wavefront Policies

Parallerism TS(並列アルゴリズム)にベクトル実行ポリシー(SIMDやGPGPU)を追加したいが、単にpar_vecをシングルスレッドに誓言スルテイ土では、制限がゆるすぎてベクトル化できないので、制限を強めた2つの実行ポリシーを追加する提案。

P0077R1: is_callable, the missing INVOKE related trait

is_callable traitsの提案。関数型をテンプレート実引数に与えると、戻り値の型を引数で関数呼び出しできるかどうかを返してくれる。

void f( int, int ) ;

std::is_callable_v< f( int, int ) > ; // true
std::is_callable_v< f( int ) > ; // false

[PDF] P0082R1: For Loop Exit Strategies (Revision 2)

イテレート文を通常通り抜けた場合(条件がfalseになった場合)と、早期に抜けた場合(break)に実行される文を記述できるようにする提案。

ループを実行したあとで、ループが全部回ったのか、途中でbreakしたのかによって、処理を分けたいことがある。その場合、以下のように書かなければならない。

auto it = get_begin(. . .); // Unfortunate that ‘it’ has to be out here.
auto end = get_end(. . .); // Unfortunate that ‘end’ has to be out here.
for (; it != end; ++it)
{
    if (some_condition(*it)) break;
    do_something(*it);
}
if (it == end) // Extra test here.
    do_stuff();
else
    do_something_else(*it);

もし、ループの条件を二回評価できない状況では、以下のようにbreakで抜けたかどうかを保持する変数を書かなければならない。

bool early = false;
while (some_condition())
{
    . . .
    if (test1()) { early = true; break; }
    . . .
    if (test2()) { early = true; break; }
    . . .
    if (test3()) { early = true; break; }
    . . .
}
if (early)
{ . . . }
else
{ . . . }

range-based forの場合はもっと悲惨だ。ループが途中で中断された時のイテレーターが欲しい場合、以下のように書かなければならない。

something_t last; // Extra construction here.
bool early = false;
for (auto&& element : container)
{
    if (some_condition(element))
    {
        last = element; // Extra copy here
        early = true;
        break;
    }
    do_something(element);
}
if (early)
    do_something_else(last);
else
    do_stuff();

そのため、この文書は、イテレート文から条件がfalseになって抜けたが、breakで抜けたかによって実行される文を記述する文法を提案している。


for ( unsigned i = 0 ; i != 10 ; ++i )
{
    if ( !do_something( i ) )
        break ;
}
catch default
{
    do_normal_exit_thing() ;
}
catch break
{// for文で宣言した変数を使うことができる
    do_break_exit_thing(i) ;
}

前回からの変更は文法だ。if forというわかりにくい文法から、catch default, catch breakというわかりやすい文法になった。

これはたまに欲しくなる。

P0088R1: Variant: a type-safe union (v6).

型安全なunion風ライブラリ、variantの提案。

variantは無効な状態、空の状態を許容するかどうかで議論がもめている。

[PDF] P0089R1: On Quantifying Memory-Allocation Strategies (Revision 2)

グローバルアロケーターのかわりにローカルアロケーターを使うことでどのような状況がパフォーマンスの向上につながるのかを検証した文書。

P0091R1: Template argument deduction for class templates (Rev. 4)

コンストラクターによるテンプレートの実引数推定の提案。

tuple<int, double> t{ 1, 2.3} ;

tuple t{ 1, 2.3 } ;

と書けるようになる。

P0096R1: Feature-testing recommendations for C++

C++の機能テストマクロをC++17に対応させる文書。

C++17に入る変更点の一覧にもなっている。

ドワンゴ広告

今日は社内で筆者のask.fmコーパスを用いて機械学習し、文章が質問かどうかを判定するプログラムの作成を試みた社員がいた。結果は、あまり精度がよくなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-03-06

靴を買った話

ボルダリングを始めてから筋肉もついたが、食事量も増えたのか、脂肪もつき始めた。その結果、体重がかなり増え、以前ならば登れていた課題が登りにくくなってきた。

これではいかんと一念発起して、2年ぶりにジョギングを再開することにした。京都に住んでいた頃はジョギングをしていたのだが、東京に引越してからはジョギングをしていなかった。まず、ジョギングをするための靴がないので、近所のスポーツ用品店に買いに行った。

スポーツ用品店には様々な靴が並んでいた。しかし疑問なのは、テニス用の靴とバスケットボール用の靴のどこが違うのだろうかということだ。

ジョギング用の靴にも、だいぶ不思議なものがあった。側面に手動のポンプがついていて、シューズをふくらませることによりフィット感を出すという触れ込みの靴があった。そのようなギミックは信用できないので買うのはやめておいた。

結局、1万円ぐらいのジョギング用の靴を買った。

さて、問題は、クライミング用の靴だ。この8ヶ月ほど、スポルティバのジーニアスを履いて登っていたが、そろそろつま先がすり減ってきた。調べると、ジーニアスのソールの厚みは3mmしかないという。足裏感覚抜群という謳い文句のためには、もちろんソールは柔らかく薄くなければならないが、3mmは薄すぎだ。また、一般的に柔らかいソースは、それだけ耐久性も劣るはずだ。

筆者のクライミングシューズ歴は、タランチュラ3ヶ月、ソリューション3ヶ月、ジーニアス8ヶ月だ。どれもスポルティバの靴なので、そろそろスポルティバ以外の靴を試してみたいものだ。

そこで今回は、あまりダウントゥのきつくない靴を試してみることにした。いろいろと見た挙句、Andrea Boldriniのアパッチライトを買うことにした。なかなか見ないメーカーだが、クライミングシューズメーカーとしては高級靴として有名なのだそうだ。価格は他の靴と比較してそれほど高いわけではないが、他の靴がここ数年で値上げしたのに対し、値段が据え置きなので、やはり相対的に高いという。

さて、アパッチライトのソールはAndrea Boldrini独自のFormulaラバーと称するものを使っている。Formulaラバーには2種類あるらしく、アパッチライトが使っているのは、摩擦と耐久性のバランスがいいと謳っているものだ。実際の感覚では、かなり硬いラバーである。摩擦はあまりよくない。アパッチライトのソースの厚みは5mmもあるそうだ。練習用のシューズとしては悪くないかもしれない。

靴の作りはそれほど極端ではない。足入れはしやすい。ソールは土踏まずの前にしか貼られていない。土踏まず部分が靴の中で盛り上がっていて、偏平足気味の筆者の足に当たる。

ヒールの作りはやや気になる。ゴムの継ぎ目の位置が中央に来ているのだが、これはヒールをかけそこねてこすった時に痛まないだろうか。また、ヒール部分は柔らかすぎて、ヒールをかけてかきこむと足が痛い。

とりあえずしばらくはアパッチライトで頑張ることにする。

2016-03-02

普通のコンピューターからAMラジオを鳴らそう

読者の持っている至って普通のコンピューターは、実はAMラジオを鳴らす発信装置が備わっている。

ラジオを鳴らすコードは以下にある。

https://github.com/fulldecent/system-bus-radio

ただしこれはMac OS Xでしか動かないので、C++11に移植したコードが以下になる。また、このコードはスレッドを回して消費電力を上げることにより、オリジナルより出力も上げてある。

https://github.com/EzoeRyou/system-bus-radio

動かし方(GCCの場合)

git clone git@github.com:EzoeRyou/system-bus-radio.git
cd system-bus-radio
make gmain
make grun

Clangの場合、以下のようにする。

make cmain
make crun

そして、AMラジオを近づけて、周波数をいろいろと変更してみよう。なんと、メリーさんの羊が聞こえるではないか。原作者の環境では1580kHz、筆者の環境では1440kHzが最も聞き取りやすかったが、コンピューターによって最適な周波数は変わる。

一体どうしてAMラジオがなるのか。CPUが命令を実行するとき、コンピューターからは電磁波が発生する。電磁波はラジオで観測できる。つまり、別のタイミングで命令を実行してやれば、ラジオに乗るノイズも別になる。適切な周波数で命令を実行すれば、ラジオに乗るノイズも音階を持ったものにできるのだ。

もともとはTEMPESTガイドラインという、アメリカ合衆国のNSAと国防省の勧告によるもので、サイドチャネル攻撃の危険性を周知しているものである。

オリジナルはMac OS X専用の高精度タイマーを使っていて、かつ、SSE命令を使っていた。C++11に移植するために、高精度タイマーには<chrono>, <thread>を使った。SSE命令の代わりに、<atomic>を使った。また、以下のPull Requestと同等のコードを書いて、スレッドで実行することにより、出力を上げた。

boost sound without radio by andryblack · Pull Request #5 · fulldecent/system-bus-radio

ドワンゴ広告

今日はこればかりやっていて、あまり仕事をしていない。これからする。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-29

C++標準化委員会の文書: P0033R1-P0059R1

P0033R1: Re-enabling shared_from_this

enable_shared_from_thisの規程を書き直す提案。

enable_shared_from_thisとは、クラスの基本クラスとして使うと、shared_from_thisというメンバー関数が追加され、そのクラスのオブジェクトを現在所有しているshared_ptrが返る。

class X : public std::enable_shared_from_this<X> { } ;

int main()
{
    auto sp1 = std::make_shared<X>() ;

    // sp1とsp2は所有権を共有する
    auto sp2 = sp1->shared_from_this() ;
}

問題は、複数のshared_ptrに所有された場合どうなるのだろうか。

X * ptr = new X{} ;
std::shared_ptr<X> sp1( ptr ) ;
std::sahred_ptr<X> sp2( ptr, [](void *){} ) ;

// sp1とsp2のどちらと所有権を同じくするshared_ptrが変えるのか?
ptr->shared_from_this() ; 

規格はこの場合の挙動について述べていない。既存の実装はすべて、sp2はsp1を上書きする。しかしこの挙動は、単にこの可能性を考えなかっただけにすぎない。Boostのshared_ptrは書きかえない。これはユーザーのフィードバックによるものである。

これを考察すると、最初のshared_ptrが所有権を持つのが自然で、デリーターが何もしないshared_ptrを作りたいことはあるかもしれず、この例が動いてほしい場合はあるが、動かないでいて欲しい場合はない。そこで、最初のshared_ptrから上書きされない決定がなされた。

また、weak_ptrを返すweak_from_thisも追加された。

P0035R1: Dynamic memory allocation for over-aligned data

operator newにオーバーアラインを守るオーバーロードを追加する提案。

問題は、この提案だとだいぶ文法が汚いことになるのではないか。

auto * ptr = new(static_cast<std::align_val_t>(32)) int[128] ;

P0037R1: Fixed-Point Real Numbers

固定少数点数ライブラリ、fixed_point<ReprType, Exponent>の提案。

P0040R1: Extending memory management tools

メモリ管理のためのライブラリとして、デストラクターを呼ぶdestroy, uninitialized_move, uninitialized_value_construct, uninitialized_default_constructを追加。これらはコア言語機能だけでも行えるが、記述が面倒なのでライブラリとしてあると便利だ。

P0046R1: Change is_transparent to metafunction (Revision 1)

連想コンテナーでheterogeneous lookupを許可するかどうかを判断するにはcomparatorにis_transparentというネストされた型名が必要だが、これをpermits_heterogeneous_lookup<T>というわかりやすいメタ関数に置き換える提案。

[PDF] P0052R1: Generic Scope Guard and RAII Wrapper for the Standard Library

汎用RAIIラッパーライブラリの提案。

#include <scope>

int main()
{
    {
        auto file = std::make_unique_resource( fopen("hoge", "w"), &fclose ) ;
    }

    {
        auto memory = std::make_unique_resource( malloc( 100 ), &free ) ;
    }

    {
        auto s1 = std::make_scope_exit( []{ std::cout << "leave scope" ; } ) ;
        auto s2 = std::make_scope_success( []{ std::cout << "leave scope normaly" ; } ) ;
        auto s3 = std::make_scope_fail( []{ std::cout << "leave scope by exception"} ) ;
    }

}

unique_resourceは、ある型のオブジェクトを保持し、破棄されるタイミングでそのオブジェクトを引数に渡してデリーターを呼んでくれる。

scoped_exitは、脱出関数を引数に取り、破棄されるタイミングで脱出関数を呼んでくれる。make_scope_xxxには3種類ある。exitはスコープから抜けたら必ず脱出関数を呼ぶ。successは例外によらずにスコープを抜けた場合にのみ脱出関数が呼ばれる。failは、例外でスコープを抜けた場合のみに脱出関数が呼ばれる。

もうひとつ、make_unique_resource_checked(R r, S invalid, D d)という関数があり、これはrがinvalidに等しい場合、返されるunique_resourceは、すでにreleaseが呼び出されたあとである。

今回の変更点は、unique_resourceのリソースとデリーターは、無例外コピー可能な型でなければならないとするもの。これにより設計が単純になり、無例外コピー可能ではないstd::functionも使う必要がなくなる。また、リファレンスを渡す場合は、std::ref/crefをユーザーが使わなければならない。

P0055R1: On Interactions Between Coroutines and Networking Library

提案されているネットワークライブラリの非同期呼び出しとしてfutureが使われているが、コルーチンを使うようにしたらオーバーヘッドが下がった上にコードも簡潔になったという文書。

[PDF] P0057R2: Wording for Coroutines

コルーチンの文面案。

[PDF] P0058R1: An Interface for Abstracting Execution

スレッドプール、協調型ファイバー、SIMD、GPGPUまで含めた実行媒体を表現できるexecutorライブラリの提案。スレッドからSIMDやGPGPUまでを包括したいいライブラリが設計できるとは思えない。

[PDF] P0059R1: A proposal to add a ring span to the standard library

ring_spanライブラリの提案。

この提案は名前が悪い。ring_viewとでも改名すべきではないだろうか。

いわゆるリングバッファーライブラリなのだが、前回の提案が固定長リングバッファーと動的リングバッファーの2つがあったのに対し、この提案では、ring_spanに統一されてしまっている。ring_spanは連続したストレージ上にリングバッファーを構築するが、ストレージの所有はしない。ストレージはユーザーが用意する。

つまりデフォルト構築もできないコンテナーなのだが、すごく使いづらい気がする。

ドワンゴ広告

来月ドワンゴで開催する予定の勉強会にレーザープリンターを持ち込みたいという猛者がいるので困惑しているが、PostScriptのデモのための実行環境としては極めて普通であり当然予期すべき事態ではある。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-27

歌舞伎座.tech #9で発表される各言語の簡易的なまとめ

3月20日に以下のような勉強会を企画した。

歌舞伎座.tech#9「異種プログラミング言語格闘勉強会」 - connpass

今回は様々な言語を持ち寄って発表する勉強会にしたかったので、有名な言語の発表枠をいくつか用意して、それ以外の言語での発表は明示的に要求させるようにした。ネタ枠として正規表現とかEsoteric的な何かの言語の発表枠も用意しておいた。

ところが、予想に反して、有名な言語の発表枠が埋まらず、発表されてから数年しか立っていないような先進的な言語やネタ言語が多かった。中には聞いたことのないような言語もあるので、Googleで検索して5分ぐらいでわかるような内容の説明を以下に並べておく。

C++(シープラスプラス)

1983年頃から、ベル研究所内でBjarne Stroustrupにより設計、開発された言語。これ以前のC with Classesの経験を元に一から作られた。我々の知る今のC++は1998年に正式に規格が制定された。そこから規格更新を繰り返して、今は2014年の規格が最新になっている。

C++は低級層のプログラミングや、パフォーマンスが重要な分野に用いられている。

JavaScript(ジャバスクリプト)

1995年に、Netscapeというブラウザーに搭載された言語。Brendan Eichにより、たったの10日間で開発されたと言われている。当初はWebサイトにクライアントサイド側でちょっとした動的なギミックを付け加える程度の用途だったのだが、今ではWebにおける共通言語の地位を確立している。

正規表現(せいきひょうげん)

歴史はコンピューター以前にさかのぼることができる。もともとは数学を記述するための言語として、1956年にStephen Cole Kleeneによって考案された。正規表現がコンピューター上で用いられるようになったのは、Ken Thompsonによって、QEDというテキストエディターの検索機能として実装されたからだ。当時のKen Thompsonの正規表現実装は、高速化のためJITが使われていたという。JITの早期の使用例としても興味深い。なお環境は、IBM 7094でOSはCompatible Time-Sharing Systemである。検索機能として正規表現によるパターンマッチは、他のツールにも取り入れられた。

C++を含む多くのプログラミング言語が正規表現ライブラリを標準で提供している。また、言語によっては、Perlのようにコア言語で深くサポートされているものもある。特に、Perlの正規表現などは、正規表現やマッチした結果を参照できるので、チューリング完全な計算力を持っている。

Esoteric(エソテリック)

これは具体的なプログラミング言語の名前ではなく、難読プログラミングの総称である。例えば有名どころの難読言語としては、Brainfuckがある。Brainfuckはチューリング完全な計算力を持っているので、計算力として根本的に他の汎用的なプログラミング言語に劣ることはない。

今回の発表でどのような言語を使うのかは、まだ知らない。

Elixir(エリキサー)

この言語は2012年に公開されたばかりで、相当に新しい。作者はJosé Valimだ。この言語の現時点でのおそらく唯一の実装はErlang VM上で動くバイトコードを生成する。Erlangの既存の資産を活用しつつ、Erlangより使いやすい言語が欲しかったのが開発動機だそうだ。

Go(ゴー)

2009年に発表された言語。Googleにより開発されていて、設計者はRobert Griesemer, Rob Pike, Ken Thompsonの3人だ。まだ言語としては発表されてから7年しか立っていないが、巨大な民間企業の後ろ盾を得た開発により、すでに現場で使えるほどの品質になっている。Googleによる実装はすでにGoでセルフホストされている。libcにも依存しないかなり独立性の高い言語となっている。

Nim(ニム)

2008年に公開された。設計者はAndreas Rumpfだ。現在の実装は、コンパイル結果としてCかC++かObjective-Cのコードを吐くようになっている。実装はNimでセルフホストされている。

Crystal(クリスタル)

2014年に公開された。設計者はAry BorenszweigとJuan Wajnermanだそうだ。文法はRubyに影響を受けている。強い静的型付けはあるが、変数の型は明示的に指定しなくて良いようになっている。

シェルスクリプト

ここでいうシェルとは、UNIXとUNIX風の環境におけるシェルのことで、そのシェルが提供する言語だ。筆者のデフォルトのシェルはbashだ。こだわりの強い情報強者たる読者はもちろんもっと強力なシェルを使っていることだろう。

ただし、この発表者のいうシェルスクリプトとは、POSIX規格の範囲内のシェルスクリプトだ。/bin/shがbashへのシンボリックリンクになっている環境も多い中で、POSIXの規程によるシェルスクリプトとプログラムだけを使ってコードを書くのは大変だ。

F#(エフシャープ)

2005年公開。主要な設計者というかプロジェクトの管理者はDon Symeだ。ML、とくにOCamlの影響を強く受けているという。実行環境としては.netフレームワーク上で動く。

歴史もそれなりに長く、Visual F#としてWindows環境でとても有名なIDEであるVisual Stdioに同梱されているそうだが、私はMLの分野をよく知らないためどの程度使われているのかわからない。

Pony(ポニー)

2013年に公開されたらしい。背景事情の情報が不足しているが、作者はおそらくSylvan Clebschではないか。

capabilities-secureな言語であると謳っているが、これは別に権限を細かく分割して必要最小限度の権限しか持たないCapability-based securityをサポートした言語という意味ではなく、単に型安全、メモリ安全、例外安全、データ競合フリー、デッドロックフリーのような意味を持つらしい。紛らわしい変な言葉を発明しないでもらいたいものだ。

Frege(フレイガ)

2011年公開。作者はIngo Wechsung。公式に、JVM用のHaskellを謳っていて、文法もほとんどHaskell互換性だ。。外部依存のないHaskellコードはそのままコンパイルできるか、僅かな修正だけで動くことを目指している。また、JVMにかかわらないFregeコードは他のHaskell実装でも実行できるのだという。

それでもHaskellという名前を使わないので、完全互換は目指していないのだろう。Fregeという名前は、Gottlob Fregeに由来する。

Rust(ラスト)

2010年に公開された。もともとの原案の設計者としてはGraydon Hoareで、開発はMozillaの支援を受けている。最初の実装はOCamlだったが、すぐにRustでセルフホストされるようになった。コード生成などのバックエンドはLLVMを使っている。

目標は、並列化処理を安全に書ける言語だそうだ。文法的にはCやC++にかなり似ている。

Nemerle(ネマール)

2003年公開。ヴロツワフ大学の学生と教授が開発したらしい。言語の名前はUrsula K. Le Guin著のゲド戦記、A Wizard of Earthsea(影との戦い)に出てくるキャラクターに由来するそうだ。英語表記ならばこの読みでいいのだろうが、ポーランド人が読むとネメレあたりの発音になるのだという。

それはともかく、言語的には.Net上で動く。関数型かつオブジェクト指向な言語だそうだ。MLの影響が強い。

Postscript(ポストスクリプト)

1982年公開。設計者はJohn Warnock, Chuck Geschke, Doug Brotz, Ed Taft, Bill Paxtonで、Adobe Systemsによって開発された。

この言語は人間が手で書くことを想定しておらず、ツールによって生成された上で、プリンターに送信される。プリンターはPostscriptを解釈してページを生成し、印刷する。Postscriptは印刷物のための中間言語としての規格だ。歴史を紐解けば、デスクトップ描画にPostscriptを使ったシステムもあったようだ。

Postscriptはチューリング完全な計算力を持つ。そのため、プログラミングは可能である。

Common Lisp

1984年公開。設計者はScott Fahlman, Richard P. Gabriel, Dave Moon, Guy Steele, Dan Weinrebだ。ANSI規格にもなっている。

軽くまとめるつもりだったが、意外と時間がかかった。

ドワンゴ広告

この記事はドワンゴ勤務外に暇だったので書いた。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-25

C++標準化委員会の文書のレビュー: P0003R1-P028R1

P0003R1: Removing Deprecated Exception Specifications from C++17

道的な例外指定を取り除く提案。

動的例外指定とは以下のような機能をいう。

void f() throw( int, double, int * ) ;

C++98の規格が制定される頃には、すでに動的例外指定の利用例はほとんどなかった。C++11で、例外指定から動的例外指定に改名された上で、deprecated扱いにされた。

十分な移行期間を与えたので、C++17で取り除く。

P0005R3: Adopt 'not_fn' from Library Fundamentals 2 for C++17

Library Fundamentals TSで提案されているVariadic Templatesを使ったnot_fnを先行して標準規格に追加する提案。

deprecated扱いされたnot1, not2と違い、引数をいくらでも取れる。

template < typename ... Types >
bool f( Types ... args ) ;

int main()
{
    auto g = std::not_fn(&f) ;

    // 任意個の引数に対応
    g(1) ;
    g(1,2) ;
    g(1,2,3) ;
}

P0009r1 : Polymorphic Multidimensional Array Reference

配列のレイアウト(FORTRANの列優先レイアウトとCの行優先レイアウト)や、構造体の配列と配列の構造体(構造体の各データメンバーがそれぞれ配列になったレイアウト)などの差異を吸収するポリモーフィックな多次元配列ラッパーである、array_refライブラリの提案。

[PDF] P0010R0: Adding a subsection for concurrent random number generation in C++17

C++の乱数ライブラリは並列アクセスできないのでその注意を文面に追加する提案。

P0018R2: Lambda Capture of *this by Value as [=,*this]

lambda式に*thisを値でキャプチャする文法の追加。

lambda式は*thisを値でキャプチャーできない。

struct S
{
    int x ;
    auto f()
    {
        return [=]{ return x ; } ;
    }
} ;

int main()
{
    std::function<int()> f ;

    {
        S s ;
        f = s.f() ;
    }

    // 実行時エラー、オブジェクトsはすでに破棄されている。
    f() ; 

}

なぜならば、コピーしている値はthisポインターであって、*thisではないからだ。上記のコードで、[=]と[&]は同じ意味になる。

そのため、新しいsimple-captureとして、*thisを追加する提案。上記のコードは、以下のように書き換えればエラーにならない。

auto f()
{
    return [*this]{ return x ; }
}

P0019R1 : Atomic View

非アトミックオブジェクトに対してアトミック操作を提供するatomic_viewライブラリの提案。既存のコードの変数の定義を変えるのが現実的ではないコードに足して現実的なライブラリ。


int data ; // 変更不可能

void f()
{
    std::experimental::atomic_view adata( data ) ;
    ++data ; // アトミック操作
}

P0020r1 : Floating Point Atomic

浮動小数点数型に対して使えるatomic_viewライブラリ。

P0024R1: The Parallelism TS Should be Standardized

<algorithm>に並列実行版を追加するParallelism TSの実装経験を検討した結果、標準規格に取り入れるべきであるとする提案。

[PDF] P0028R1: Using non-standard attributes

attirbuteの名前空間の省略記法の提案。

独自のattributeトークンを使った独自拡張は、トークンの重複を防ぐためにattribute名前空間を使うことが多い。

void f() {
    [[rpr:: kernel, rpr:: target(cpu,gpu)]]
    do task();
}

しかし、attribute名前空間をいちいち指定するのは面倒なので、using宣言に相当するような機能がほしい。そこで、この提案は、そのような機能を付け加える。

void g() {
    [[ using rpr: kernel, target(cpu,gpu)]]
    do task();
}

キーワードはとりあえずusingにしているが、変わるかもしれない。

ドワンゴ広告

来月はドワンゴのセミナールームでだいぶ血の気のあらそうな勉強会が開催されます。

歌舞伎座.tech#9「異種プログラミング言語格闘勉強会」 - connpass

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-23

C++標準化委員会の文書: N4568-N4577

P4568: PL22.16/WG21 draft agenda: 29 Feb-05 Mar 2016, Jacksonville, FL/US

Jacksonville会議の予定のドラフト

[PDF] N4569: Working Draft, C++ Extensions for Ranges

コンセプトを使ったRangeライブラリの提案。個人的には現状のコンセプトがあまり気に入っていないので延期されてほしい。

[PDF] N4570: Oulu Meeting Information

2016年6月にフィンランドのOuluで開かれる会議の案内。

[PDF] N4571: 2016-11 Issaquah meeting information

2016年11月にアメリカ合衆国ワシントン州Issaquahで行われる会議の案内。

[PDF] N4572: WG21 telecon meeting: Pre-Jacksonville

Jacksonville会議前の2時間の電話会議の予定。

N4573: 2017-02 Kona WG21 Meeting Information

2017年2月にハワイで行われる会議の案内。

[PDF] N4575: Networking TS Working Draft

Boost.Asioを元にしたネットワークライブラリのTSへの提案。

[PDF] N4576: Networking TS Editor's Report

ネットワークライブラリTSの編集者の報告書。P0112R1からの変更点は、組版の修正。

[閲覧は標準化委員限定][PDF] N4577: Technical Specification for C++ Extensions for Concurrency

futureにthenとかwhen_allなどのメンバーを追加したり、latchとbarrierを追加したり、atomic_shared_ptrを追加したりする非同期まわりのライブラリ拡張TS。閲覧には標準化委員であることが必要。

ドワンゴ広告

標準化委員会の文書のレビューもしたいのだけれど今は別用もある。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-22

歌舞伎座.tech#9「異種プログラミング言語格闘勉強会」開催のお知らせ

しばらく勉強会を開催していなかったので、3月20日に勉強会を企画した。以下のconnpassから参加登録ができる。

歌舞伎座.tech#9「異種プログラミング言語格闘勉強会」 - connpass

今回の勉強会は、銀座松竹スクエアの13Fにあるドワンゴのセミナールームで開催する。去年まで、ドワンゴのセミナールームは歌舞伎座タワーにあったのだが、今年から松竹スクエアという歌舞伎座タワー近くの別の建物に移転した。開催場所が歌舞伎座ではないのに歌舞伎座.techとはこれいかにとツッコミたくなるところだが、「歌舞伎座周辺で開催される技術勉強会」という言い訳が上司から提供された。

今回の勉強会のタイトルは、歌舞伎座.tech#9「異種プログラミング言語格闘勉強会」だ。

これまでC++に特化した勉強会を開催してきたが、さすがに毎回C++だけというのもどうかと思い、今回は前々からやってみたかった勉強会を開催することにした。すなわち、様々な言語を一つづつ発表するというものだ。普段は遭遇しない分野に遭遇できるいい機会を作れるのではないかと考えている。

今回は、有名どころの言語をある程度抑えつつ、Perl 6, 正規表現、何らかのEsoteric言語の発表枠も入れてみた。すべての発表枠が埋まるかどうかはわからない。また、自分の好きな言語の発表枠がない事態に備えて、「俺の好きな言語がないけしからん発表枠」も追加した。

追記:

発表後の反応から、少し方針を変更した。

この勉強会では、様々な言語を取り扱う。それぞれの言語枠で発表する人は、以下のような内容の発表が期待される。

  • 如何にして私は心配するのをやめてこの言語を愛するようになったのか
  • 他の言語と比較したこの言語の優位性
  • この言語ならでは特色、楽に書ける処理
  • 知名度の低い言語の場合、言語そのものの紹介

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-02-18

Appleのマーケティングに騙されてはいけない

Appleがアメリカで容疑者のコンピューターの暗号解除に協力するよう裁判所命令を出されたかどで、Appleは顧客のプライバシーとセキュリティを脅かす命令だとして反対する公開声明をだしている。世間はAppleの顧客のプライバシーとセキュリティを守るようにみえる姿勢を賞賛しているようだ。

しかし騙されてはいけない。これはAppleのマーケティング戦略に過ぎない。Appleは顧客のプライバシーとセキュリティを守る技術的な最善の努力を一切果たしていないので、プライバシーとセキュリティを気にかける人間はApple製品を使ってはならないのはもちろんである。

そもそも、Appleは国家政府に秘密裏に協力していた前科がある。今更顧客のプライバシーを守る云々などと言い出したのは、アメリカ政府による監視の実態を告発した真のアメリカの愛国者Snowdenの登場以降である。顧客のプライバシーとセキュリティをないがしろにしていたのが公になったから、マーケティング上の利益のためにこういった姿勢をみせているに過ぎない。

そもそも、今回のAppleに対する裁判所命令とはなにか。Appleは技術的に実質不可能な暗号解読を命じられたわけではない。今回の技術的な話はこうだ。

ある事件の容疑者のApple製のコンピューターのストレージは暗号化されている。このコンピューターには、復号するためのパスワードの入力に連続して規定回数以上失敗するとデータを消去する仕組みがある。アメリカ国家政府は、可能な限りのパスワードの組み合わせを試してパスワードを探し当てるブルートフォース攻撃をするために、Appleにパスワードの連続した入力間違いでデータ消去を発生させる仕組みを無効にする協力を要求しているのだ。

これは、おそらくAppleにとって技術的に可能である。この仕組みは、おそらくファームウェアかOSで実装されているはずだ。Appleのコンピューターは、ファームウェアとOSに対して、Appleが署名したバイナリでなければ実行されない仕組みになっているはずで、今回アメリカ政府がAppleに要求しているのはそのためだろう。

Appleが本当に顧客のプライバシーとセキュリティを重要視するのであれば、バイナリ署名の鍵はAppleが全顧客で共通の鍵を使うのではなく、顧客が作成、管理するようになっているはずだ。それをしないからこういうことが起こるのだ。

そもそも、今のスマフォにはベースバンドプロセッサーという、まだセキュリティ意識の低かった1990年台に設計された基地局と通信するためのブラックボックスなCPUとソフトウェアが別に積まれている。セキュリティとプライバシーに気を使う人間が携帯電話を所有することはありえない。

まして、Appleの製品は、ソフトウェアが不自由である。ソフトウェアが信頼できるかどうかは、実際に検証されなければならないが、その検証作業を妨害している。

結論:Appleのあの宣言はSnowden以後のマーケティング戦略に過ぎない。

2016-02-11

Warner Music、ハッピーバースデーの歌の著作権を保有していないことを認めて訴訟を降りる

Warner Music Pays $14 Million to End 'Happy Birthday' Copyright Lawsuit - Hollywood Reporter

アメリカ合衆国で、有名なハッピーバースデーの歌(Happy Birthday To You)の歌の著作権使用料を請求していたWarner Musicに対し、同歌の歴史ドキュメンタリーを作成していた映画監督のJennifer Nelsonが、Warner Musicは著作権を有していないとしてクラスアクション訴訟を起こした。

この訴訟では、Warner Musicの提出した、著作権の委託管理を受けたという証拠となる出版物の肝心な部分が画像がやたらボケているので、現物を入手してみたところ、ボケた部分にはWarner Musicの主張するような記述がなかったという証拠まで提出されている。

2016-02-06

最近遊んだ不自由なビデオゲーム

不自由なゲーム専用OSであるWindows箱で最近遊んだゲームを紹介する。

Keep Talking and Nobody Explodes

爆弾解体ゲーム。ビデオゲームというよりはボードゲームに違い。ビデオゲーム側としては、爆弾を解体する操作を提供している。このゲームを遊ぶには最低二人が必要である。一人がコンピューターを操作して爆弾を解体する。爆弾を解体する人は、爆弾の解除マニュアルを読むことができない。

残りのプレイヤーは、できれば紙に印刷された爆弾解除マニュアルを読む。そして、爆弾を解体する人間と、口頭で通信して爆弾を解除させる。

爆弾解除マニュアルは不必要に回りくどく書かれている。そのため、爆弾解除係とマニュアル読者は不毛なやり取りを繰り返すことになる。例えば、以下は典型的なプレイ中の会話である。

マニュアル係「どんなモジュールがある?」
解体係「えーと、何か線がいっぱいあるやつがある」
マニュアル係「線は横? 縦?」
解体係「横」
マニュアル係「線は何本?」
解体係「5本」
マニュアル係「えーと、最後の線は黒い」
解体係「えーと、線は上から白、赤、黄色、赤、黒」
マニュアル係「最後の線の色は?」
解体係「黒」
マニュアル係「えーと、箱のどこかにシリアルナンバーがあるはずなのだけど」
解体係「シリアルナンバー?」 マニュアル係「そのシリアルナンバーの最後の桁は奇数?」
解体係「シリアルナンバー・・・あ、あった、でなんだっけ?」
マニュアル係「そのシリアルナンバーの、えーと、最後の桁は奇数」
解体係「最後の桁は・・・4」
マニュアル係「4は・・・偶数なので奇数じゃないか。次行って・・・赤い線はある?」
解体係「ある」
マニュアル係「何本ある?」
解体係「2本」
マニュアル係「えーと、じゃこれも違って・・・黒い線はある?」
解体係「ある」
マニュアル係「ということは・・・えーと、最初の線を切って」

これはとても面白い。

BioShock Infinite

待望のBioShockシリーズの第三段。だが期待されすぎた凡作。

グラフィックと音楽はいいのだが、戦闘が極めて退屈で、ストーリーも大して面白くない。エリザベスも可愛くない。

Kerbal Space Program

宇宙開発をするゲーム。ロケットを組み立てて地上から発射し、軌道に載せ、惑星探索をするゲーム。

舞台は地球のような恒星系を持つ惑星Kerbinから始まる。Kerbinは地球の10分の1のサイズなのに表面重力は同じというとても密度の高い物質で構成されている。

とても面白くて中毒性のあるゲームだが、筆者はまだ軌道にすらのせることができていない。軌道は極めて常識に反する。

Grapple

粘性のある球体がGrappling hookを駆使しながらスタートからゴールに移動するだけの面クリア型ゲーム。とても単純だがとても面白い。

Tower of Guns

ランダム生成されるステージ群をクリアしていくFPS。極めて単純だが面白く、息抜きに良い。

2016-02-05

往年のDOSマルウェアをDOSエミューレーター上で実行できる博物館

電子データの収集保存活動をしているInternet Archive(archive.org)が、1980年台、1990年台に流行した秀逸な画面効果を持つDOSマルウェアをブラウザー上でエミュレーターDOSBoxを使い安全に実行可能な状態で展示している。

The Malware Museum : Free Software : Download & Streaming : Internet Archive

とても興味深い。

2016-02-01

Archユーザー、rm -rfしてMSIのラップトップのUEFIのバグを発見する

No POST after rm -rf / / Kernel & Hardware / Arch Linux Forums

No POST after rm -rf / | Hacker News

Mount efivarfs read-only · Issue #2402 · systemd/systemd

Archのインストールを消去したかったので、遊びのためにMSIのラップトップで"rm -rf --no-preserve-root /"してみたArchユーザーのラップトップが文鎮化してしまった。なぜだ。

調査の結果、おそらく/sys/firmware/efi/経由でEFI変数(EFIの規格で定められているマザーボードが提供する小容量の不揮発ストレージ)に書き込みを行ったためだと判明した。

EFI変数に書き込むのは、EFI規格上完全に合法な操作であるが、どうやらファームウェアの不具合で、このMSIのラップトップでEFI変数に書き込むと文鎮化してしまう不具合があるらしい。

3年前にも似たようなことが話題になっていた。本当にEFIの現実の実装はクソだ。

本の虫: UEFIとLinuxの現状

もはやここまで現実の実装がクソであると、EFI規格は脆弱性を発生させるために国家の諜報機関によって意図的に複雑にされていることを疑いたくなる。

2016-01-31

闘会議2016のアナログゲームのとある運営スタッフの感想

闘会議2016のアナログゲームのインスト要員として2日間運営スタッフとして入っていたので、その感想を書く。

筆者は江添亮、ドワンゴにエンジニアとして雇われている。ドワンゴのボードゲーム同好会のメンバーでもある。今年の闘会議でも、アナログゲームは設置される。もちろんカタンもある。カタンのインストをするために運営スタッフとして参加した。

今回の闘会議には不安が大きかった。なにしろ、今回のアナログゲームエリアには、30卓ほど立てるという予定である。1卓にスタッフを2人配置するとして、60人必要になる計算だ。60人ものボドゲがインストできるスタッフをどこから集めてくるというのか。あまりにも無謀すぎる。私が一切関わっていない会社の企画するイベントが失敗するのは私の知ったことではないが、カタンのインストが失敗し、カタンに悪い印象を与える事態だけは、ガチのカタンプレイヤーとして見過ごすことはできぬ。そこで、カタンのインストのために運営スタッフとして参加した。

今回の闘会議では、ドワンゴのエンジニアには動員がかからなかったので、社内からはボドゲをインストできるスタッフがせいぜい5,6人程度しか出なかった。60人ものインスト要員をどうやってまかなうつもりなのだろうか。

私「そもそも必要なだけの頭数はいるのか?」
企画「5,60人ほどいます」
私「そのうちボドゲ経験があってインストができる人は?」
企画「3分の1ぐらい・・・コネで集めました」
私「残りは?」
企画「派遣バイトです」

嫌な予感しかしない。

ボードゲームの上手なインストは、ある程度のボードゲーム経験とインスト経験を必要とする。経験が全てではないが、最低限のボードゲーム慣れ、場慣れする必要がある。派遣バイトの中にボードゲーム経験のある人間がどのくらいいるだろうか。第一、どうやって募集しているのだ。「闘会議、アナログゲームエリアでボードゲームの解説と、場合によってはプレイヤーとしても参加して場を盛り上げてもらうお仕事です!」といった具体的な告知があれば、まだボードゲーム経験のある人間や、説明慣れしている人間が集まりやすそうではある。しかし、もし単なる「闘会議イベントの運営スタッフです!」程度の告知であったならば、イベントの運営スタッフ慣れしている人は応募するだろうが、ボードゲーム経験は望めそうにもない。

「で、バイトは前日のリハーサルに来るの?」
企画「全員来ます」
「すると前日のリハーサルで我々がバイトにインストして、翌日にインストしてもらうのか」
企画「そうです」

大丈夫なのだろうか。初対面の人間に複雑なルールの説明をする作業というのは、人によっては不得意な作業である。思うに、必要なのは少しの経験による場慣れだと思うのだが、今回は、その少しの経験を詰むほどの時間もない。

そして極めて絶望的なことに、この会話が行われたのは、闘会議までもう数えるほどしか日数がない時点である。根本的にスケジュールがおかしい。

そして前日リハーサル。私は今年木場に引っ越したので、闘会議の会場である幕張メッセのある海浜幕張までは、だいぶ近くなった。東西線で西船橋まで行き、JRに乗り換えて、武蔵野線で南船橋に行き、京葉線で海浜幕張に行く。タイミングが良ければ、西船橋から直通運転で一本で海浜幕張まで行けることもある。

私は予定通り西船橋で降りて乗り換えた。そして南船橋まで着いたが、何故か電車がホームに止まったまま、なかなか発車しない。しばらく待った結果、とうとう発射したが、なんともと来た線路を戻っていくではないか。しまった。これは南船橋が終点で西船橋に折り返しているのだ。こうして、予定より遅れて会場に到着した。

さて、肝心の派遣バイトだが、やはりボドゲ経験のある人は皆無であった。ボードゲームによっては、日本語の説明書が付属していないものまである。ボドゲのインストを始めるが、やはり完全にボドゲ未経験では、マニュアル読み上げのような説明になってしまいわかりづらい。

カタンは、私の他にもう一人、カタンを5,6回ぐらいプレイしたことがある人間がインストをするようだ。カタンは最低100回ぐらいはやらないと感覚がつかめない。

さて闘会議1日目の朝、私は正しい電車の乗り換えに成功して会場に着いた。小雨が振っており極めて寒い。異様なほどに寒い。ここまで寒いと客足が遠のくのではないかと思われるぐらい寒い。幕張メッセの中は、強力な暖房に温かいのだが、外は死ぬほど寒い。

開場して人がなだれ込んでくる・・・かと思いきや、それほどの人数ではない。やはり天候が客足に影響を与えているのだろうか。それとも、今回は借りているホールが多いので、相対的に人が少なくみえるのだろうか。

去年に引き続き、麻雀は人気だ。すぐに卓が成立する。ボドゲの成立には少し待たねばならない。程なくしてボドゲ卓も埋まった。

カタンのルールをすべて口頭で説明すると30分ほどかかる。それに、口頭で説明されたことをすべて覚えられるわけがない。そこで、基本的なルールだけ教えて、後はプレイしながら教えていく方法を取った。これならば最初の何もしない状態での説明は5分か10分ほどですむ。

また、今回のカタンのインストを通じて、カタンでは初期配置が非常に重要だという認識を新たにした。ダイスの確率の説明は最初に行っているのだが、やはりカタンは数百回ほどやらないと感覚がつかめないのか、初心者は確率の極めて悪い場所に初期配置しようとする。去年の闘会議では、極端に確率が悪い場所に設置したものだけ助言をしていた。その結果、プレイヤーによって初期配置に極端な差が生まれ、トップを妨害する暇もなく30分ほどでゲームが終了してしまうことがたまに見られた。

今回は、何百回もカタンを対戦している筆者の感覚で、確率、資源バランス、港、目かぶり、他プレイヤーの影響まで含めた初期配置を強力に助言した。その結果、なんと初心者が4人集まった卓であっても、中盤から終盤にかけてのトップ阻止のどんでん返しが何度も起き、ガチ勢が経験するものと同じ極めて熱い戦いになった。

なるほど、カタンは初期配置が極めて重要なのだ。一人でも初期配置が悪いプレイヤーがいると、あるプレイヤーが極端に有利になりすぎてバランスが崩れ、張り合いのないプレイに成り下がってしまう。1番手、2番手に本来残るはずのない良い2件目の建設場所を与えてしまったり、3番手4番手に本来残るはずのない1件目の建設場所を与えてしまったりする。

ちなみに、一回だけ、カタンを所有していて家でよく遊んでいると主張する母と息子の親子2人で参加しておきながら、筆者の助言を聞かず、「置きたいところに置けばいいじゃない」とつぶやきながら、親子揃って悪い配置をした親子がいたが、親子揃って終盤まで全く伸びずに勝ち目がなかった。プレイ中の建設戦略も極めて悪く、序盤から意味もなくThe Longest Roadだけを狙って無駄な建設したりしていた。The Longest RoadとThe Largest Armyは補助的な点数であって、序盤から無理に狙いに行くものではないのだが、この辺の感覚は、強いプレイヤーと数百回の対戦をしないとわからない。カタンを所有していてよく遊んでいるとはいえ、適切な上達者の指導がなく、弱い初心者同士が狭い世界で戦っていると、こういう袋小路に陥る。大抵のゲームにありがちの問題だ。

さて、小学生ぐらいの子供が卓に着いた。子供にカタンのルールを教えるのは難しい。カタンはそれほど難しいゲームではないが、6面ダイスを2つ振った出目の合計値の確率から、戦略や得点方法まで、様々な馴染のない要素を理解させなければならない。将棋やチェスのような有名なボードゲームならば、戦略書がすでに山ほど出ていて、ある程度まで強くなるには、先人が考えぬいた結果の定石の暗記とパターンマッチだけですむのだが、カタンなどのボードゲームの場合、ルールをその場で聞いて理解し、自分で与えられたルールの範囲内で柔軟に戦略を考えなければならない。ただし、筆者の経験では、闘会議のアナログゲームの上級エリアにわざわざ来るぐらいの子供は、そういう処理も得意であるようだ。この子はどうだろう。

筆者「カタンはやったことあるかな?」
子供「はい、去年の闘会議ではじめてやりました」
筆者「何、ひょっとして私がインストした?」
子供「はい、そうです」

なんと、去年私がカタンを教えた子供が今年もやってきてカタンをするというのか。

うおおおおおおおお!!!!! 自分は今猛烈に感動している。

しかも、去年より遥かにうまくなっているし、結果として勝利したではないか。圧倒的にいい話だ。

1日目の最後は、人が集まらなかったので筆者もプレイヤーとして参加した卓で、閉場までの時間が残り僅かしかない状態で猛烈なトップへの妨害と勝利争いになり、最終的に筆者が勝利した。このゲームは極めて劣悪な盤面で、鉄が固まっているが、8鉄以外は確率が悪く、麦が不作であった。筆者は8土と土港を序盤で確保して、勝利を確信したのだが、当然残りの3人の注意を惹きつけてしまい、序盤の盗賊の標的にされた上に、中盤では8が全く振られることがなかった。終盤でトップの勝ちを阻止するためにThe Longest Roadの激しい奪い合いになり、また終盤の最後で、これまでの不足分を取り返すかのように8が出始めて巻き返し、中盤は盗賊と8が振られないことにより完全に死んでいたことから妨害の注意がそれていたために勝利した。

こうして闘会議の1日目が終わり、寒さに震えながら帰路についた。帰り道が同じであった自転車好きの同僚と自転車について話をしていて、自宅から職場まで5kmなので、十分に自転車通勤が可能な距離であるが、自転車を買う決心がつかないため、いまだに自転車通勤できていないことを話すと、「ぜひ自転車通勤するべきだ。まずは安い20万ぐらいの自転車を買って始めるといい」と言われた。自転車に20万も出すとは。しかもそれが安いだと。住んでいる世界が違う。ゲームPCの値段であれば安いのだが。

帰路、海浜幕張から南船橋で乗り換えようとして、別のホームに向かってしまい、発射直前の列車にろくに確認もせず飛び乗った結果、海浜幕張に逆戻りしてしまった。また、帰りの電車で傘をなくしてしまった。

闘会議2日目

朝に木場から海浜幕張に向かう。西船橋で乗り換えをして乗った電車は、何か違和感がある。行き先を見ると市川塩浜駅となっている。これは逆方向だ。南無三、また間違えたか。市川塩浜駅で降りて、逆方向の列車に乗ることで、海浜幕張まで一本で到着した。

2日目も1日目と同様にカタンのインストをした。帰りの電車は間違えなかった。

去年の感想。

本の虫: 闘会議2015のアナログゲームエリア、とある運営スタッフの感想

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-24

グラビティリサーチ銀座に行ってきた

銀座に最近できた新しいクライミングジムのグラビティリサーチ銀座に行ってきた。

GRAVITY RESEARCH 銀座 | クライミング(ボルダリング・スポーツクライミング)ジム グラビティ リサーチ GRAVITY RESEARCH

このクライミングジムの最大の特徴は、銀座にあるということだ。職場が銀座の場合、仕事上がりに登るのに最適だ。

入会金が1500円で、21時以降の料金が1600円。他のジムと比較すると深夜料金が高い気がするが、これは税込み料金であることと、銀座にあるということと、職場が銀座で平日の仕事上がりに他のジムに行く場合、交通費が別にかかるということを考えると、こんなものかもしれない。

ジムの中はそれほど広くはないが、壁の横幅と課題の数はそれなりにあった。ただし天井が低い。

課題はグレードに対して簡単であるように感じた。

職場から歩いていける距離にあるという店で、グラビティリサーチ銀座は価値のあるジムだ。もし午前中からやっているのであれば、朝ボルダリングが可能だったのだが、残念ながら、14:30から開店する。

定期会員になって、平日毎日30分ぐらいの短時間利用するのは悪くなさそうだが、残念ながら3ヶ月単位でしか定期購入できない。一ヶ月ならばその月は集中して登るのもありなのだが、さてどうしよう。

ところで、このジムにはドワンゴのボルダリング同好会として同僚3人で行ったのだが、宛名「ドワンゴ ボルダリング同好会」で領収書を書いてもらったところ、「ボルダリング同好会って何をするんですか?」と聞かれた。はて、ボルダリング同好会を名乗る団体がクライミングジムに来ている。これ以上に自明なことがあるだろうか。

第2回 ドワンゴからの挑戦状の予選に参加した

第二回、ドワンゴからの挑戦状の予選に参加した。公式Webサイトは以下の通り。

第2回 ドワンゴからの挑戦状 | 株式会社ドワンゴ

もう予選は終わってしまったが、問題は今からでも挑戦することができる。問題に挑戦するには以下のWebサイト上から行う。

Welcome to 第2回 ドワンゴからの挑戦状 予選 - 第2回 ドワンゴからの挑戦状 予選 | AtCoder

これは高橋直大さんの会社、AtCoder社の運営する競技プログラミングのWebサイトで、今回の競技プログラミングのジャッジシステムと問題作成のためにAtCoder社に協力してもらっている。

問題は、A, B, C, D, Eの5問あり、それぞれに点数が設定されている。CDE問題には、部分点も設定されてる。

回答をするには、問題とプログラミング言語を選び、ソースコードを貼り付けて提出すると、atcoderのサーバー側でコンパイルとテストケースに対する実行が行われて、結果がみられる。問題を解くためには、まずソースコードのコンパイルやパースに失敗しないこと、正しい回答を出力すること、実行時間、メモリ使用量が制限以内であることが求められる。

この予選の上位入賞者は、2月13日にドワンゴ本社で行われる本選に参加できる。本選での上位入賞者には賞金が出るほか、2017年度新卒である場合、ドワンゴへの新卒採用における一部の面接をパスできる。

去年行われた際、筆者は予選終了後に問題を解いたが、今回はリアルタイムで予選に参加した。筆者は競技プログラミングは得意ではないが、難易度が去年と同じ程度である場合、仮にもドワンゴでエンジニアという役職で雇用されている以上、B問題ぐらいまでは解けなければ沽券に関わる。

A: ニコニコ数

問題分だけ抜粋すると、以下の通り。

ニコニコ数とは、10進法で表記したときに 2 と 5 が交互にあらわれ、かつ一番上の位が 2 で一番下の位が 5 であるものです。 例えば、 25,2525,252525252525252525 などはニコニコ数であり、 467,5252,5 などはニコニコ数ではありません。

ニワンゴくんは、 N 以下の正の整数のうち、約数にニコニコ数を持つものがいくつあるかを調べようと思いました。ニワンゴくんに代わって、この問題を解くプログラムを作ってください。

筆者はこの問題を以下のように読み間違えてしまった。

ニワンゴくんは、 N 以下の正の整数それぞれについて、すべての約数のうちニコニコ数である数字の合計値がいくつあるかを調べようと思いました。

つまり、筆者の誤った解釈では、2525はニコニコ数となる約数として25と2525を持つので、出力すべき数字の合計値に2を足すべきだとなる。そのため、2525を超える値について、出力が間違ってしまった。そして、解釈間違いに気がつくまでに、実に不毛な考察が行われた。結果が32bit符号付き整数に収まらないのではないか。いや、Nは10の9乗以下であるので問題はない。どこかにコンパイルエラーにならないタイプミスがあるのか。などなど。

さて、正しい解釈でこの問題を考えると、ニコニコ数2525は約数として25を含むし、252525も約数として25を含む。したがって、約数として25が含まれるかどうかのみを考えればよい。約数の25が含まれる値は25の倍数であるし、単純にNを25で割ればよい。

#include <iostream>
 
int main()
{
    unsigned N{} ;
    std::cin >> N ;
    std::cout << N /25 << std::endl ;
}

B: 積み鉛筆

問題分はリンク先を参照してもらうとして、A問題に時間をほとんど使い尽くしてしまったので、B問題を解く時間が30分ぐらいしか残されてない。

さて、これは一体どうすればいいのだろうか。整合性を保つために手直しをすると、前の鉛筆まで手直しが発生するのではないか。するとバックトラック的な何かをする必要があるのだろうか。

ぼんやりと鉛筆を詰んでいる図の例をながめていると、ふとひらめいた。

2本の上段の鉛筆KiとKi+1に対して、下段の整合性を保つ必要のある鉛筆は、LiとLi+1とLi+2の3本だけだ。Li+2の長さをKi+1とKi+2の都合で変えても、Liを整合性を保つために変更する必要はない。そして、整合性を保つ方法というのも、KiとKi+1の長さを、Li+1とLi+2に入れて、それで整合性が取れなければ、LiとLi+1に入れるだけでいいのではないか。2つの連続した鉛筆Kに対しては、その下の3本の鉛筆Lしか考慮しなくてよい。

さっそくそのようなコードを書き、投稿。なぜかWA(Wrong Answer)とTLE(Time Limit Exceeded)の嵐。何がまずいのか。入力をすべてメモリ上に読み込んでいるからまずいのか。そんなことをせずに逐次に処理をしていくべきなのか。いや、入力は10の5乗程度でしかなく、TLEを起こすはずがない。WAはなぜだ。少なくとも問題の入力例に対しては正しい答えを出せているのだが。

そしてここで時間切れとなった。時間切れ後に気がついたのだが、どうやらB問題の回答をA問題に対して提出していたようだ。B問題に対してそのまま提出すると、普通に通った。なんということだ。

実質B問題まではできたと言えるので、最低限の沽券を守ることはできた。

C: メンテナンス明け

残念ながら、私はC問題以降を解説するだけのアルゴリズム力を持たない。しかし、C問題についてはいろいろと面白い裏話を聞いている。

この問題は、ドワンゴ社内でtayamaというハンドルネームを用いているドワンゴ社員によって作成された。

問題を作成してAtCoderに提出したところ、AtCoderの高橋直大社長から、「何のひねりもない問題」と言われたそうだ。tayamaさんはこれを、「アルハラ(=アルゴリズム・ハラスメント)である」とコメントしている。

また、この問題は、本来D問題にする予定で作ったのだが、直大社長に、「簡単じゃない?」と言われたためC問題になったのだという。

また、この問題には入力の大小に応じて、SmallとLargeというテストケースが用意されており、それぞれに点数が設定されている。テストケースが弱く、Smallには通らないのにLargeに通るコードが書けてしまうそうだ。

また、テストケースに、"small/91_tayama_killer_00"という名前のテストがあるが、これは問題作成者であるtayamaさんの当初書いた回答コードに通らない例が発見されたために追加されたテストケースだそうだ。

さて、本選は2月13日にドワンゴ本社で行われる。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-20

C++標準化委員会の文書のレビュー: P0160R0-P0172R0

P0160R0: Wording for removing defaults for unary folds

fold式からデフォルト値を削除する文面案。

P0162R0: A response to "P0055R0: On Interactions Between Coroutines and Networking Library"

「現在提案中のBoost.Asioベースのネットワークライブラリの状態保持のための動的ストレージは、コルーチンのスタック上に確保すれば高速になるので、規格でそのように規程すべきだ」という提案に対し、「そのような設計は実装の自由度を制限してしまい好ましくない。同等の高速化はBoost.Asioのカスタムアロケーターでも可能で、最近のAsioはデフォルトのアロケーターを使った場合でも最適化を自動的にするようになっているので、規格でもそのように規定しよう」という反論。

P0163R0: shared_ptr::weak_type

shared_ptr<T>に対応するweak_ptr<T>のネストされた型名、weak_typeを追加する提案

shared_ptrからweak_ptrを作るには、weak_ptrの型を具体的に記述する必要があった。これではジェネリックなコードを書きにくいので、N4537ではshared_ptrに対応するweak_ptrを返すunlockというメンバー関数を追加する提案をしたが、これは却下された。

しかし、やはりweak_ptrの型を直接書くのは嫌なので、今度はshared_ptrに対応するweak_ptr型のweak_typeというネストされた型名を追加する。

つまり、以下のようなコードを解決する。

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    std::weak_ptr<???> wptr = sptr ; // 型がわからない。
}

この問題を解決するために、従来、以下のようなコードが書かれてきた。

template < typename T >
std::weak_ptr<T> unlock( std::shared_ptr<T> const & sptr )
{
    return std::weak_ptr<T>( stpr ) ;
}

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    auto wptr = unlock(sptr) ;
}

この提案を使えば、以下のように書ける。

template < typename T >
void f( T & t )
{
    auto sptr = t.get_shared_ptr() ; // 何らかのshared_ptrが返される
    auto wptr = typename decltype(sptr)::weak_type(sptr) ;
}

unlockの方がわかりやすい気がするのだが。

P0164R0: Core Motions

Core issuesに対する解決の中で規格入りする準備ができたもの一覧

P0165C++ Standard Library Issues to be moved in Kona

Library issuesに対する解決の中で規格入りする準備ができたもの一覧

P0166R0: Three interesting questions about contracts

関数にprecondition, postcondition, invariantを記述できるcontract機能を使って、どのようにvectorのようなクラスで範囲外チェックを記述できるのかというHerb Sutterの提示した問いに答える文書。

P0167R0: Core "ready" Issues

2015 Kona会議以降に規格入りする準備が整ったcore issueの解決の一覧。

P0169R0: regex with Unicode character types

regexをUnicode(char16_t, char32_t)に対応させるために必要な設計の考察。

char32_tはUnicodeコードポイントをほぼそのまま表現できる。basic_regex<char32_t>を実現するには、<locale>をchar32_tに対応させる必要がある。具体的には、ctype<char32_t>, collate<char32_t>, collate_byname<char32_t>を実装する必要がある。

char16_tの方は、char32_tのように実装さえすれば動くわけではない。UTF-16にはサロゲートペアが存在するので、char16_tの一つのオブジェクトは1文字を表現しない場合がある。しかし.(dot atom)とか\S(predefined character class)はサロゲートペアの片割れにマッチしてしまう。サロゲートペアがあるため、char16_tは<locale>をサポートできない。

UTF-16ではなく、UCS-2(サロゲートペアのない16bit固定長Unicode符号。BMPだけをサポートしたもの)をサポートするという案は採用できない。なぜならば、UCS-2はすでにISO/IEC 10646においてdeprecated扱いされているため、今から発行する規格がUCS-2だけをサポートするというのはありえない。

ではどうするのか。basic_regex<char16_t>は提供せず、char16_tとchar32_tを相互変換するイテレーターを提供するという案がある。

他には、char16_tは、現行のbasic_regex<char>と同じく、可変長エンコードをそのまま突っ込んだものとみなし、特に何も対応せずそのまま提供するという案もある。この案を採用する場合、Unicodeに関してはchar32_tに変換した上でbasic_regex<char32_t>を使うべきだ。

筆者の意見では、UTF-8, UTF-16, UTF-32を簡単に変換できる関数と、相互に通過的に変換するイテレーターを提供した上で、正規表現を使いたければbasic_regex<char32_t>に一本化する方法がいいと思う。

P0170R0: Wording for Constexpr Lambda

constexpr lambda式の文面案。

auto f = []( int x ) { return x ; } ;
constexpr int i = f(0) ; // OK

P0171: Response To: Resumable Expressions P0114R0

Resumable Expressionに対して寄せられた懸念事項に答える文書。

言語規格がスケジューリングまで定めるべきではないという意見に対しては、提案しているのはシンタックスシュガーだけで、スケジューリングの詳細はライブラリが実装すると回答。

resumable関数を呼び出す際にawaitを書き忘れると、実に不具合箇所を特定しにくい不具合の元になるという意見に対しては、現在提案中の戻り地を無視すると警告する[[nodiscard]]のような属性を提案すればよいと回答。

P0172R0: Abominable Function Types

C++の型システムには、コンパイラー開発者とメタプログラマーしか知らない闇がある。Abominable functionと名付けられた型のことだ。

abominable functionとは、CV修飾やリファレンス修飾された関数型のことだ。

using regular = void () ;
using abominable = void () const volatile && ;

非メンバー関数はCV修飾やリファレンス修飾することはできない。しかし、関数型はCV修飾、リファレンス修飾ができてしまう。

このようなabominable function型は、ほとんど利用価値がないが、traitsを実装する際に個別に対応しなければならないため、問題になる。

このAbominable functionをどうにかしようと問題提起する文書。

ドワンゴ広告

1月23日にはドワンゴ主催のプログラミングコンテストが行われる。

第2回 ドワンゴからの挑戦状 | 株式会社ドワンゴ

前回と同じく、競技プログラミングの環境にはあのAtCoder(株)の社長であり最強最速アルゴリズマー養成講座の著者でもある高橋直大氏のAtCoder (アットコーダー)を利用している。

このコンテストの予選を突破し、2月13日の本選の上位入賞者の2017年新卒には、採用試験の一部免除などの特典があるそうだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-18

C++標準化委員会の文書のレビュー: P0144R0-P0159R0

P0144R1: Structured Bindings

多値を返す関数の戻り値を簡単に変数に束縛できるようにするための文法の提案。

現在、C++ではtupleがあるために、多値を返す関数を簡単に宣言することができ、また簡単に多値を返すことができる。

std::tuple< T1, T2, T3 > f( )
{
    T1 a{} ; T2 b {} ; T3 c { }
    return { a, b, c } ;
}

見ればわかる通り、極めて簡単だ。

呼び出し側で多値を受け取るのも、比較的簡単である。

T1 a ; T2 b ; T3 c ;
std::tie( a, b, c ) = f() ;

確かに、比較的簡単ではあるが、このコードはいろいろと問題がある。

変数をあらかじめ宣言しなければならない。もし、型がPOD型ならば、未初期化の状態となり、お作法上あまりよろしくない。

型がクラス型の場合、デフォルト構築が行われる。その直後にコピー/ムーブして上書きするのに、デフォルト構築するのは無駄だ。

そこで、複数の変数の宣言と、その変数群を多値のそれぞれの値で初期化する新しい文法を追加する提案。

現在、以下の文法が提案されている。

auto { a, b, c } = f() ;

この宣言文は、変数、a, b, cを宣言する。変数の型はそれぞれ独立して初期化子から推定される。

この提案では、以下の2つの新しい文法を提案している。

auto { list-of-comma-separated-variable-names } { expression };
auto { list-of-comma-separated-variable-names } = expression;

expressionは、tupleとpairの場合、それぞれの要素で型推定され、初期化される。式は変数と同じ個数の要素をもたなければならない。

std::pair< T1, T2 > p{ ... } ;
auto { a, b } = p ;

std::tuple< T1, T2, T3 > t{ ... } ;
auto { x, y, z } = t ;

式には、クラス型を指定することもできる。このときクラス型のすべての非staticデータメンバーはアクセス可能で、ひとつの基本型(そのクラス型も含む)で宣言されていなければならない。

struct X { int a ; double b ; } ;

X x{ 0, 0.0 } ;

// aはint、bはdouble
auto { a, b } = x ;

クラスが無名unionメンバーを含む場合、最初のメンバーが選ばれる。


struct X
{
    union { int i ; double d ;} ;
    int data ;
} ;

X x{ {0}, 0 } ;

// xはint型で値は0
auto { x, y } = x ;

autoにCV修飾子やlvalueリファレンス修飾子を使うこともできる。

auto const { x, y, z } = f() ;
auto const & { x, y, z } = f() ;

rvalueリファレンス修飾子のサポートについては、議論中。

この文法は、initializer_listからの初期化はサポートしない。

braced-init-listからの初期化もサポートしない。

// サポートしない
auto { x, y, z } = { 1, 2, 3 } ;

理由は、この文法を追加するのは簡単であるが、この文法の有益な利用例がいまのところないため。

再帰的な構造化解除はサポートしない。

std::tuple< T1, std::tuple< T2, T3>, T4 > f() ;

// サポートしない
auto { a, {b, c}, d } = f() ; 

将来の拡張案としては興味深い。

[PDF] P0145R0: Expression Order of Evaluation

式のオペランドの評価順序を固定する提案。

たとえば、f( a, b, c )という式があるとき、オペランドf, a, b, cがどの順番で評価されるのかは、規格上は未規定(unspecified)とされていた。そのため、シークエンスポイントを隔てることなく、2つのオペランド中の式が同じオブジェクトを変更するとき、挙動は未定義となる。例えば、f( i++, i )のような式で、iが整数型の変数の場合、挙動は未定義となる。v[i] = i++も同じだ。

f( i++, i )やv[i] = i++のような昔からよく知られた問題ばかりではない。例えば、以下のようなコードの挙動も未規定だ。


#include <map>

int main()
{
    std::map< int, int > m ;
    m[0] = m.size() ; // #1
}

#1が評価された後のmapの中身はどうなっているだろうか。{{0,0}}だろうか、{{0,1}}だろうか。規格上は未規定だ。

式の評価順序が未規定という問題は、単にプログラマーの娯楽とか、採用試験とか、学術的な興味にとどまる問題ではない。現在の規格の制約は、現実の日常的なプログラミングに問題を引き起こしている。例えば以下のコードだ。

void f()
{
    std::string s = “but I have heard it works even if you don’t believe in it”
    s.replace(0, 4, “”).replace(s.find(“even”), 4, “only”).replace(s.find(“ don’t”), 6, “”);
    assert(s == “I have heard it works only if you believe in it”);
}

s.replace(...).replace(...).replace(...)と、いわゆる"method chaining"的なメンバー関数呼び出しの仕方をしている。これらがすべて、ひとつの式の中のサブ式であるので、その評価順序は未規定である。評価順序が未定義な以上、assertは引っかかる可能性がある。findの後に、そのfindを含まない別のreplaceが評価されるとassertに引っかかる。

このコードの問題点は、極最近になってツールで検証した結果明らかになった。

このコードは、Bjarne StroustrupのThe Programming Langauge 4thに載っているコードであり、この本は世界屈指のC++専門家達によって査読されていた。そのような環境ですらこの問題が発覚しなかったということは、現在の規程に問題がある。

このようなメソッドチェイニングが問題なのだとする批判は当たらない。なぜならば、std::cout << e1 << e2 << e3のような式も影響を受けるし、std::future<T>はメソッドチェイニングを前提としたthen()メンバー関数を追加する予定である。問題はメソッドチェイニングではない。

しかし、評価順序の未規定ルールは、何十年も存在する。なぜ今変えるのか。当時の制約ある環境では、この規程は理由があるものであった。時代と環境が変わった今、当時は適切だった規程が適切ではなくなっている。そのために変える必要がある。

この文書が提案する評価順序は以下の通り。

  • 後置式は左から右に評価される。これには関数呼び出し式とメンバー選択式も含まれる。
  • 代入式は右から左に評価される。これには複合代入も含まれる
  • シフト演算子のオペランドは左から右に評価される。

結果として、以下の式はすべて、a, b, c, dの順に評価される。

a.b
a->b
a( b, c, d )
b @= a
{ a, b, c, d }
a[b]
a << b
a >> b

オーバーロードされた演算子を使った式の評価順序は、組み込み演算子の評価順序と同じになる。関数呼び出しと同じ順序ではない。

P0147R0: The Use and Implementation of Contracts

現在提案されているcontracts案と似たような文法を使ってどのようなコードが書けるかという例示のための文書。contractsは、関数が満たすべきpreconditions, invariants and postconditionsを記述できる。

[PDF] P0148R0: memory_resource_ptr: A Limited Smart Pointer for memory_resource Correctness

memory_resourceをラップするスマートポインター、memory_resource_ptrの提案。

memory_resourceとは、ライブラリに追加される各種ヒープメモリーを実装したクラスのポリモーフィックな基本クラスだが、生のポインターを使うのはいろいろと不便なので、memory_resourceに特化したスマートポインターを追加する。

[PDF] P0151R0: Proposal of Multi-Declarators

多値を個々の変数で受け取る宣言文法として、以下のようなものがP0144で提案されている。

std::tuple< T1, T2, T3 > f() ;
auto { a, b, c } = f() ;

この文書は、以下のような別の文法を提案している。

tuple<T1, T2, T3><T1 x, T2 y, T3 z> = f(); // 多値のクラスと変数型の明示的な指定
tuple<T1, T2, T3><x, y, z> = f(); // 多値のクラスの明示的な指定
<T1 x, T2 y, T3 z> = f(); // 変数型の明示的な指定
<x,y,z> = f(); // 明示的な指定なし

また、使わない変数の省略を認めている。

// 2番めの変数は無視される
<a, c> = f() ; 

個人的には、autoキーワードを使う文法のほうがわかりやすいし、この文法が提案している柔軟な機能にどの程度の需要があるのか疑問だ。

P0152R0: constexpr atomic<T>::is_always_lock_free

コンパイル時にatomic<T>が常にロックフリーかどうかを確認できるconstexprメンバー関数is_always_lock_freeを追加する提案。

P0153R0: std::atomic_object_fence(mo, T&&...)

atomic_thread_fence(memory_order)に似ているが、指定したオブジェクトのみsequenced before関係を発生させるatomic_object_fence( memory_order, T && ... )の提案。

P0154R0: constexpr std::hardware_{constructive,destructive}_interference_size

std::hardware_constructive_interference_sizeとstd::hardware_destructive_interference_sizeの提案。

この2つのconstexpr関数は、一般にキャッシュラインサイズと呼ばれている値を取得するためのもの。

2つのオブジェクトがあり、ランタイムアクセスパターンがそれぞれ異なる(例えばあるオブジェクトは頻繁に変更するのに、もう一方のオブジェクトはほとんど変更しない)とする。CPUのキャッシュはキャッシュラインサイズと呼ばれる単位で行われており、この2つのアクセスパターンの異なるオブジェクトが同じキャッシュライン上に載っている場合、一方のアクセスパターンに引きづられて、本来必要のないキャッシュからメモリへの書き込みが行われてしまう。これをfalse-sharingと呼ぶ。

false-sharingを避けるには、異なるキャッシュライン上にオブジェクトが配置されるために、オブジェクトの配置されるメモリアドレスに十分なオフセットを儲けなければならない。hardware_destructive_interference_sizeは、false-sharingを避けるために必要な最小限のオフセットサイズを教えてくれる。

逆に、2つのオブジェクトのランタイムアクセスパターンが似通っていて、同じキャッシュライン上に載っている場合を、true-sharingと呼ぶ。true-sharingが行われるためには、2つのオブジェクトの合計サイズがキャッシュラインサイズに収まらなければならない。

hardware_constructive_interference_sizeはtrue-sharingされるための上限のサイズを教えてくれる。

この2つの値の定義は、実質の同じ意味なので、同じ値になるのではないかと思うのだが、2つに分けたのは、単にコードの意図をわかりやすくするためだろうか。それともこの値の異なる環境が実際に存在するのだろうか。

[PDF] P0155R0: Task Block R5

fork-join並列コードを書くためのライブラリ、task_blockの提案。

例えば、ツリー構造を並列実行でたどるときに

template<typename Func>
int traverse(node *n, Func&& compute)
{
    int left = 0, right = 0;
    define_task_block([&](task_block& tb) {
        if (n->left)
            tb.run([&] { left = traverse(n->left, compute); });
        if (n->right)
            tb.run([&] { right = traverse(n->right, compute); });
    });
    return compute(n) + left + right;
}

このように、define_task_blockに関数オブジェクトを渡すと、task_blockが実引数に渡される。あとはそのメンバー関数のrunを実行するたびに並列に実行が分岐する。

P0156R0: Variadic lock_guard (Rev. 2)

lock_guardをVariadic Templatesにする提案。

std::mutex m1, m2 ;

void f()
{
    // m1, m2に対してlock()が呼び出される
    std::lock_guard<std::mutex, std::mutex> lock( m1, m2 ) ;
    // 処理

    // lockのデストラクターでm1, m2にunlock()が呼び出される。
}

なお、make関数はない。lock_guardはコピーもムーブもできないからだ。

P0157R0: Handling Disappointment in C++

ある関数が呼び出し元の期待する処理を完了できなかった場合、呼び出し元は失望(disappointment)する。関数はその失望をどのようにして呼び出し元に伝えるのか。

この文書は、慣習的に使われている通知方法を列挙して考察している。

戻り値

戻り値は、最も一般的なC言語的手法であり、大抵はintかenumが使われる。失敗時には成功時特別可能な特別な値が使われる。この通知方法には問題がある。

エラー処理と通常の処理とが混ざってしまう。エラー処理が面倒なため、プログラマーはエラーを無視したがる。エラー処理に戻り値を使うと、通常の結果の値を戻り値ではなく実引数を経由した上書きで渡す必要が出てくる。呼び出し元がエラー通知に反応するには、事前に通知される値について知っていなければならない。

特別な戻り値

C言語で慣習的に用いられている方法で、戻り値を通常の結果通知に使うと同時に、特別な値を使って、エラー通知にも使う方法だ。特別な値には、nullポインターやゼロや-1などが用いられる。

この方法で通知できるのは、たいていはエラーの有無だけであり、エラーの具体的な内容については、別の方法で通知しなければならない。別の方法には、errnoのようなグローバルなオブジェクトが使われる。これは並列化を阻害する。

実引数を経由したエラー通知

これもC言語で慣習的に行われている方法で、実引数にエラー通知を受け取るためのオブジェクトへのポインターを取る方法だ。

これは、ループ文の条件式の中で使えないとか。エラー通知を完全に無視まではできないものの、結局無視されやすいという問題はある。

多値

関数の結果と、エラー通知の両方を多値で返す。これは古典的なC言語では行われていない方法だが、Goのような最近の言語では組み込みの多値を返す機能があるために使われている。

long jump

エラー通知にlong jumpを使う例が存在する。long jumpは関数内で起こった状態を解消するための手段を持たず、関数内で状態を持たないか、エラー発生時に状態を無視していい、極めて制限された環境でしか使えない。

例外

例外は上記のエラー処理の問題をいくつも解決している。通常のコードとエラー処理コードを分離できる。戻り値の型にデフォルトコンストラクターが要らない。補足されなかった例外はコールスタックを上がっていく。例外は未知のエラー通知にも使える。スタックフレームを遡る例外通知は、ローカルのオブジェクトを破棄していくため、エラー専用の破棄処理がいらない。

例外には欠点もある。まず例外は重い処理であるということ。頻繁に発生する「失望」を例外で伝えるには重すぎる。例外の存在は関数呼び出しにオーバーヘッドを発生させるので、極めて資源制約の強い環境では使えない。

エラーに対処してもう一度試行する処理を書けない。

論文では、様々なエラー処理を比較した結果、今後の規格は、現在提案中のexpectedやstatus_valueのような多値を返すエラー処理を推奨している。

P0158R0: Coroutines belong in a TS

コルーチンには様々な問題が山積みで、C++17に直接追加するのは時期尚早であるので、TSとして出すべきだと主張する文書。

現在コルーチンに持ち上がっている様々な問題が列挙されている。

Technical Specification for C++ Extensions for Concurrency, DTS

複数のfutureがready状態になるまで待つwhen_all、複数のfutureのうちどれかひとつがready状態になるまで待つwhen_any、futureのmethod chaining的に使えるメンバー関数then、wait_for, wait_untillatchとbarrier、atomic_shared_ptrといった並列同期に関するライブラリのTS。

ドワンゴ広告

今日は雪だったが、いつもどおりドワンゴ標準時で出社した結果、特に影響はなかった。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-12

C++標準化委員会の文書のレビュー: P0100R1-P0136R1

今回も改訂版文書のレビューをしていく。改定前の文書のレビューは同番号の過去の記事を参照。

本の虫: C++標準化委員会の文書のレビュー: P0100R0-P0109R0

P0100R1: Comparison in C++

比較の強さ別にカスタマイゼーションポイントとなる関数を用意する提案。

比較には、同一比較と、順序比較がある。順序比較には、partial orderとweak orderとtotal orderがある。これまで、順序比較にはoperator <などの演算子が、その種類を問わず使われてきた。どの比較を提供できるかは、型により異なるので、比較ごとの方法を提供できる関数テンプレートを追加する。カスタマイズするには、これをオーバーロードすればよい。

template<typename T> bool partial_less(const T&,const T&);
template<typename T> bool weak_less(const T&,const T&);
template<typename T> bool total_less(const T&,const T&);

template<typename T> bool partial_unordered(const T&,const T&);
template<typename T> bool weak_equivalence(const T&,const T&);
template<typename T> bool total_equal(const T&,const T&);

P0112R1: Networking Library (Revision 7)

Boost.Asioをベースにしたネットワークライブラリの提案。

変更点は、io_serviceをio_contextに、wrap()をbind_executor()に改名。package()をuse_futureの関数呼び出し演算子に、const_buffers_1とmutable_buffers_1クラスの廃止。const_bufferとmutable_bufferが直接要件を満たすことに鳴った。const_bufferとmutable_bufferにdate()とsize()メンバー関数を追加。buffer_cast<>とbuffer_size()の代替案。

P0136R1: Rewording inheriting constructors (core issue 1941 et al)

継承コンストラクターの文面を書き直す提案。これにより継承コンストラクターの挙動が僅かに変わるそうだが、影響はほぼない。

ドワンゴ広告

そういえば、今年からドワンゴで勉強会にも使っているセミナールームは歌舞伎座タワーではなく、ADK松竹スクエアの13階に変更になっている。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-11

GCC 6にインデントミスの警告機能が追加

GCC 6にインデントミス警告の機能が追加された。ドキュメントのコミットログは以下の通り。

gcc.gnu.or g Git - gcc.git/blobdiff - gcc/doc/invoke.texi

このインデントミスの警告機能は、-Wmisleading-indentationオプションで有効にできる。

if ( condition )
    foo() ;
    bar() ; // 警告

具体的に説明すると、この機能は、if, else, while, forの中の文がブロック文ではなく、かつ、文に続いて同じインデントのif, else, while, forではない文が続く場合に警告する。

例えば、以下のようなコードは、for文のオペランドとしての文に続いて同じインデントレベルの文が続くが、for文なので警告は出ない。


const std::size_t I = 10, J = 10, K=10 ;
int a[I][J][K]

for ( std::size_t i = 0 ; i != I ; ++i )
for ( std::size_t j = 0 ; j != J ; ++j )
for ( std::size_t k = 0 ; k != K ; ++k ) // 警告なし
{
    a[i][j][k] = 0 ;   
}

この警告は、プリプロセッサーにより生成された結果のコードには適用されない。

if ( condition )
    foo() ;
#if CONDITION
    bar() ; // 警告なし
#endif

理由は、プリプロセッサーによって生成された結果のコードは機械的に生成されたもので、人間が読むものではないから、人間向けのインデントは意味をなさないからだ。

ドワンゴ広告

今日は祝日で休みだ。

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0

2016-01-09

Linus Torvalds、Microsoftが「ジャンプしてみろよ」と言えばIntelとAMDはジャンプする

LKML: Linus Torvalds: Re: [PATCH 0/3] TLB flush multiple pages per IPI v5

IntelのCPUのTLBの挙動に、頻出するパターンにおける最適化らしきものが施されていることが観測できることに対して議論した後で、

前にも言ったように、Transmetaで働いていた時期、俺はNT以前のWindowsがどういう世界だったかということを垣間見た。GDI protection traversalはGDIがカーネル側に入るたびにTLBを全部フラッシュするらしく、また当時の一部のグラフィックベンチマーク(これはまだハードウェア支援されたVGAグラフィックが一般的ではなかった時代のことだ)は、5千から1万命令以内にTLBを全部ふっとばす実装になっていた。そのため、IntelとAMDはTLB fillを高速にするために多大な労力を割くだけの理由があった。なぜならば、GDIベンチマークは当時重要だったからだ。当時のグラフィックベンチマークというのは、基本的な2Dウインドウ処理やフォント描画のベンチマークのことだ。

RISCベンダーは全く気にしなかった。奴らと来たら完全にクソなハードウェアで、ソフトウェアパートナー(大方はデータベース)に、ソフトウェアを変更して、large-pageを使うようにしたり、TLBミスを回避すべく努力させた。奴らのコンパイラーはロードを早期に行い、ストアを遅延させた。というのも、メモリサブシステムは完全にオモチャだったからだ。TLBミスはパイプライン全体をぶっ壊すなどしていた。本当にクソなハードウェアで、まだ期待している奴もいる。残念なことだ。

Windowsの業界では、そんなことは望みようがなかった。Microsoftが、「おう、ジャンプしてみろよ」と言ったならば、IntelとAMDはどちらも「どれだけ高く飛べばいいのでしょうか?」と言ったものだ。結果として、x86はどのRISCよりも柔軟だった。なぜならば、IntelとAMDはどんなクソなソフトウェアでも実行しなければならなかったからだ。ソフトウェア開発者に最適化をさせる代わりに。

ドワンゴ広告

ドワンゴは本物のC++プログラマーを募集しています。

採用情報|株式会社ドワンゴ

CC BY-ND 4.0: Creative Commons — Attribution-NoDerivatives 4.0 International — CC BY-ND 4.0