#include #include #include #include #include #include #include #include #include namespace fs = std::filesystem; std::string colors(std::string str) { std::map colors = { // Gray, Red, Green, Yello, Blue, Magenta, Cyan, White {'A',"30;1"}, {'R',"31;1"}, {'G',"32;1"}, {'Y',"33;1"}, {'B',"34;1"}, {'M',"35;1"}, {'C',"36;1"}, {'W',"37;1"}, // Same but without bold {'a',"30"}, {'r',"31"}, {'g',"32"}, {'y',"33"}, {'b',"34"}, {'m',"35"}, {'c',"36"}, {'w',"37"}, // Italic, parameter shortcut {'i',"3"}, {'P',"32m\x1b[3"}, }; bool show = isatty(STDOUT_FILENO); for(size_t i = 0; i < str.size() - 2; i++) { if(str[i] == '<' && str[i+1] == '>') str.replace(i, 2, show ? "\x1b[0m" : ""); else if(str[i] == '<' && str[i+2] == '>' && colors.count(str[i+1])) str.replace(i, 3, show ? "\x1b[" + colors[str[i+1]] + "m" : ""); } return str; } Buffer::Buffer(): size {0}, data {nullptr}, path {"(none)"} { } /* Empty buffer initialized with given byte */ Buffer::Buffer(size_t bufsize, int fill) { size = bufsize; char *buffer = new char[size]; memset(buffer, fill, size); data = std::shared_ptr(buffer); path = "(anonymous)"; } /* Buffer initialized from file */ Buffer::Buffer(std::string filepath, ssize_t bufsize, int fill) { char const *path = filepath.c_str(); int fd = open(path, O_RDONLY); if(!fd) throw std::runtime_error(format("cannot open '%s'", path)); struct stat statbuf; ssize_t x = fstat(fd, &statbuf); if(x < 0) { close(fd); throw std::runtime_error(format("cannot stat '%s'", path)); } size = (bufsize < 0) ? statbuf.st_size : bufsize; size_t size_to_read = std::min(size, (size_t)statbuf.st_size); /* Read buffer and fill whatever is left */ data = std::shared_ptr(new char[size]); memset(data.get(), fill, size); x = read(fd, data.get(), size_to_read); close(fd); if(x != (ssize_t)size_to_read) { throw std::runtime_error(format( "error while reading '%s'", path)); } this->path = filepath; } Buffer::Buffer(std::string filepath, std::vector const &folders, ssize_t size, int fill): Buffer() { for(auto &f: folders) { fs::path p = fs::path(f) / fs::path(filepath); if(fs::exists(p)) { /* Hopefully this will use the move assignment */ *this = Buffer(p, size, fill); return; } } char const *path = filepath.c_str(); throw std::runtime_error(format("cannot find '%s' in library", path)); } /* Create a buffer by copying and resizing another buffer */ Buffer::Buffer(Buffer const &other, size_t new_size, int fill): Buffer(new_size, fill) { memcpy(data.get(), other.data.get(), std::min(new_size, other.size)); } /* Generic timer which returns times in ns using CLOCK_REALTIME */ struct timespec timer_start(void) { struct timespec start; clock_gettime(CLOCK_REALTIME, &start); return start; } long long timer_end(struct timespec start) { struct timespec end; clock_gettime(CLOCK_REALTIME, &end); long long ns = 1000000000 * (end.tv_sec - start.tv_sec); ns += end.tv_nsec - start.tv_nsec; return ns; } /* Format ns durations to us, ms or s depending on the value */ std::string timer_format(long long duration) { if(duration < 2000) return format("%lld ns", duration); duration /= 1000; if(duration < 2000) return format("%lld us", duration); duration /= 1000; if(duration < 2000) return format("%lld ms", duration); duration /= 1000; return format("%lld s", duration); }