サブプロセス処理をパイプを使わずに行う

| |パイプとかファイルディスクリプタとか、そーゆー低レイヤーのはなし|
|:--|:--|
|boost::processの子プロセスの入力を閉じる|https://qiita.com/cielavenir/items/9219162170cf2dd8b144|
|サブプロセス処理をパイプを使わずに行う|https://qiita.com/cielavenir/items/0e69848b705fafec86e1|
|fstreamのファイルディスクリプタを取得する<br>ムーブコンストラクタしかないクラスのprotectedメンバを呼び出す|https://qiita.com/cielavenir/items/fe892c564e6b12983776|

boost::processをコピーできないならこういう書き方もできると思います。ファイルを削除してもfdは生きるという特性に依存するのでUnix専用になりますが…。

```cpp
// g++ zstd.cpp -lboost_thread -lboost_system -lboost_filesystem
// zstd < input_file | ./a.out (and compare printed string to original SHA1)

#include <iostream>
#include <fstream>

#include <boost/uuid/sha1.hpp>
#include <boost/algorithm/hex.hpp>

#include <boost/process/system.hpp>
#include <boost/process/io.hpp>
#include <boost/process/pipe.hpp>

#include <boost/iostreams/copy.hpp>
#include <boost/thread.hpp>

#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;

unsigned int byteswap32(unsigned int n){
    const unsigned int m8=0x00ff00ff;
    const unsigned int m16=0x0000ffff;
    n=((n&m8)<<8)|((n>>8)&m8);
    n=((n&m16)<<16)|((n>>16)&m16);
    return n;
}

int _SubprocessFilterPushthread(const std::string &cmd, std::istream &in, std::ostream &out){
    boost::process::opstream enc;
    boost::process::ipstream dec;
    boost::process::child c(cmd, boost::process::std_in < enc, boost::process::std_out > dec);
    auto fpush = [&]{
        /// write to enc ///
        boost::iostreams::copy(in, enc);
        /// flush enc ///
        enc.flush(); // flush is immune to opstream::rdbuf() issue.
        //enc.rdbuf()->sync();
        enc.pipe().close();
    };
    boost::thread(boost::ref(fpush));
    boost::iostreams::copy(dec, out);
    c.wait();
    return c.exit_code();
}

int _SubprocessFilterPopthread(const std::string &cmd, std::istream &in, std::ostream &out){
    boost::process::opstream enc;
    boost::process::ipstream dec;
    boost::process::child c(cmd, boost::process::std_in < enc, boost::process::std_out > dec);
    auto fpop = [&]{
        boost::iostreams::copy(dec, out);
    };
    boost::thread(boost::ref(fpop));
    boost::iostreams::copy(in, enc);
    enc.flush();
    enc.pipe().close();
    c.wait();
    return c.exit_code();
}

int _SubprocessFilterTmpfile(const std::string &cmd, std::istream &in, std::ostream &out, bool inIsFile){
    FILE* ftmpwrite = NULL;
    int fd = _GetFstreamFd(in);
    if(fd<0){
        ftmpwrite = tmpfile();
        fd = fileno(ftmpwrite);
    }
    std::string writename = std::string("/dev/fd/")+std::to_string(fd);
    if(ftmpwrite){
        std::ofstream fw(writename.c_str(),std::ios::out);
        boost::iostreams::copy(in, fw);
        fw.close();
    }
    FILE* ftmpread = tmpfile();
    std::string readname = std::string("/dev/fd/")+std::to_string(fileno(ftmpread));

    int r = system((cmd+(inIsFile?" \"":" < \"")+writename+"\" > \""+readname+"\"").c_str());
    std::ifstream fr(readname.c_str(),std::ios::in);
    boost::iostreams::copy(fr, out);
    fr.close();
    fclose(ftmpread);
    if(ftmpwrite){
        fclose(ftmpwrite);
    }
    return r;
}

int main(){
    std::stringstream ss;
    //_SubprocessFilterPushthread("zstd -d",std::cin,ss);
    //_SubprocessFilterPopthread("zstd -d",std::cin,ss);
    _SubprocessFilterTmpfile("zstd -d",std::cin,ss);

    {
        boost::uuids::detail::sha1 hash;
        unsigned int digest[5];
        hash.process_bytes(ss.str().data(), ss.str().size());
        hash.get_digest((boost::uuids::detail::sha1::digest_type)digest);
        for(int i=0;i<5;i++)digest[i]=byteswap32(digest[i]);
        std::string result;
        boost::algorithm::hex((char*)digest, ((char*)digest) + 20, std::back_inserter(result));
        std::cout << result << std::endl;
    }

    return 0;
}
```