Skip to content

Instantly share code, notes, and snippets.

@manzyun
Last active March 20, 2017 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save manzyun/183df65c808413bca052fc68821aeab7 to your computer and use it in GitHub Desktop.
Save manzyun/183df65c808413bca052fc68821aeab7 to your computer and use it in GitHub Desktop.
Rewriting humansize.py to C++ from Dive into Python3. But, I can not compiling... I can not C++.
/* Origin: Your first Python program - Dive Into Python 3
* http://www.diveintopython3.net/your-first-python-program.html
*
* Original Source:
* http://www.diveintopython3.net/your-first-python-program.html
*/
#include <memory>
#include <iostream>
#include <map>
#include <array>
#include <string>
#include <exception>
void init(){
std::map <int, std::array<std::string, 8>> SUFFIXES;
std::array<std::string, 8> human = {"KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
std::array<std::string, 8> digital = {"KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"};
SUFFIXES.insert(std::make_pair(1000, human));
SUFFIXES.insert(std::make_pair(1024, digital));
delete human;
delete digital;
}
std::string approximateSize(int size, bool* a_kilobyte_is_1024_bytes = true) {
/* Convert a file size to human-readable form.
*
* Keyword argments:
* size -- file size in bytes
* a_kilobyte_is_1024_bytes -- if true (default), use multiples of 1024
* -- if false, use multiples of 1000
*
* Returns: std::string
*/
if(size < 0){
throw std::value_error("number must be non-negative");
}
std::unique_ptr<int> multiple = std::make_unique<int>();
multiple = a_kilobyte_is_1024_bytes ? 1024 : 1000;
for(auto suffix = SUFFIXES[multiple].begin(); suffix != SUFFIXES[multiple]; ++suffix) {
std::unique_ptr<int> size = std::make_unique<int>();
size /= multiple;
if(size < multiple){
std::unique_ptr<std::string> str_size = std::make_unique<std::string>();
std::unique_ptr<std::string> str_suffix = std::make_unique<std::string>();
std::unique_ptr<std::string> re_str = std::make_unique<std::string>();
str_size = std::to_string(size);
str_suffix = std::to_string(suffix);
re_str.append({str_size, ' ', str_suffix});
return re_str;
}
}
}
int main() {
init();
std::cout << approximateSize(1000000000000, false) << std::endl;
std::std::cout << approximateSize(1000000000000) << std::endl;
delete SUFFIXES;
}
@yumetodo
Copy link

yumetodo commented Mar 20, 2017

動くように直したもの

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

修正のポイント

  • 元のコードの raise ValueError('number too large') が次元のはざまに飲み込まれているようなので、追加
  • sizeが負の場合に例外を投げるのではなく、最初からunsignedな型を使う
  • std::mapではなくstd::unordered_map
  • std::arrayはdeleteしない、というかnewしてないのにdeleteするな。そしてnewもdeleteも書くな。
  • 謎のstd::unique_ptrがあるが、何がしたいのか謎。ヒープへのメモリー確保は現代においてものすごく重いので避けるべし。
  • std::to_stringだと浮動小数点の文字列化のときに精度を指定できないので、仕方なくstd::stringstreamとマニピュレータを使うように。fmtlib/fmt使いたい。
  • C++にもpythonのfor...inに当たるRange based-forがあります
  • C++にはinitizer_listがあるので、init関数いらないし、無駄にグローバル変数作らない。

@yumetodo
Copy link

気持ち高速化したもの

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

改善点

  • よく見たらもとのpythonのコード、snake_caseじゃんか、ならばこっちもそれに合わせる。
  • operator overeloadを利用し、処理をoperator<<に移すことで、std::stringstreamを一旦作ったりという中間オブジェクト生成を減らし微かに高速化

@yumetodo
Copy link

std::unordered_mapを使わない版

http://melpon.org/wandbox/permlink/52jPbw1uCscAX3Sp

改善点

  • よく考えたらサフィックスは2通りしかないんだから、要素2の配列にして引数のboolをoperator[]にそのまま渡すだけでいいやん。
  • ということはその配列の構築、コンパイル時にできるよ!
  • サフィックスの文字列をstd::stringに変換する作業が大幅に減ったよ!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment