@@ -1432,6 +1432,158 @@ FMT_FUNC auto vformat(string_view fmt, format_args args) -> std::string {
1432
1432
}
1433
1433
1434
1434
namespace detail {
1435
+
1436
+
template <typename T> struct span {
1437
+
T* data;
1438
+
size_t size;
1439
+
};
1440
+
1441
+
#ifdef _WIN32
1442
+
inline void flockfile(FILE* f) { _lock_file(f); }
1443
+
inline void funlockfile(FILE* f) { _unlock_file(f); }
1444
+
inline int getc_unlocked(FILE* f) { return _fgetc_nolock(f); }
1445
+
#endif
1446
+
1447
+
// A FILE wrapper. F is FILE defined as a template parameter to make system API
1448
+
// detection work.
1449
+
template <typename F> class file_base {
1450
+
public:
1451
+
F* file_;
1452
+
1453
+
public:
1454
+
file_base(F* file) : file_(file) {}
1455
+
operator F*() const { return file_; }
1456
+
1457
+
// Reads a code unit from the stream.
1458
+
auto get() -> int {
1459
+
int result = getc_unlocked(file_);
1460
+
if (result == EOF && ferror(file_) != 0)
1461
+
FMT_THROW(system_error(errno, FMT_STRING("getc failed")));
1462
+
return result;
1463
+
}
1464
+
1465
+
// Puts the code unit back into the stream buffer.
1466
+
void unget(char c) {
1467
+
if (ungetc(c, file_) == EOF)
1468
+
FMT_THROW(system_error(errno, FMT_STRING("ungetc failed")));
1469
+
}
1470
+
};
1471
+
1472
+
// A FILE wrapper for glibc.
1473
+
template <typename F> class glibc_file : public file_base<F> {
1474
+
public:
1475
+
using file_base<F>::file_base;
1476
+
1477
+
// Returns the file's read buffer as a string_view.
1478
+
auto get_read_buffer() const -> span<const char> {
1479
+
return {this->file_->_IO_read_ptr,
1480
+
to_unsigned(this->file_->_IO_read_end - this->file_->_IO_read_ptr)};
1481
+
}
1482
+
};
1483
+
1484
+
// A FILE wrapper for Apple's libc.
1485
+
template <typename F> class apple_file : public file_base<F> {
1486
+
private:
1487
+
auto offset() const -> ptrdiff_t {
1488
+
return this->file_->_p - this->file_->_bf._base;
1489
+
}
1490
+
1491
+
public:
1492
+
using file_base<F>::file_base;
1493
+
1494
+
auto is_buffered() const -> bool {
1495
+
return (this->file_->_flags & 2) == 0; // 2 is __SNBF.
1496
+
}
1497
+
1498
+
auto get_read_buffer() const -> span<const char> {
1499
+
return {reinterpret_cast<char*>(this->file_->_p),
1500
+
to_unsigned(this->file_->_r)};
1501
+
}
1502
+
1503
+
auto get_write_buffer() const -> span<char> {
1504
+
if (!this->file_->_p || offset() == this->file_->_bf._size) {
1505
+
// Force buffer initialization by placing and removing a char in a buffer.
1506
+
fputc(0, this->file_);
1507
+
--this->file_->_p;
1508
+
++this->file_->_w;
1509
+
}
1510
+
auto size = this->file_->_bf._size;
1511
+
FMT_ASSERT(offset() < size, "");
1512
+
return {reinterpret_cast<char*>(this->file_->_p),
1513
+
static_cast<size_t>(size - offset())};
1514
+
}
1515
+
1516
+
void advance_write_buffer(size_t size) {
1517
+
this->file_->_p += size;
1518
+
this->file_->_w -= size;
1519
+
}
1520
+
};
1521
+
1522
+
// A fallback FILE wrapper.
1523
+
template <typename F> class fallback_file : public file_base<F> {
1524
+
private:
1525
+
char next_; // The next unconsumed character in the buffer.
1526
+
bool has_next_ = false;
1527
+
1528
+
public:
1529
+
using file_base<F>::file_base;
1530
+
1531
+
auto is_buffered() const -> bool { return false; }
1532
+
1533
+
auto get_read_buffer() const -> span<const char> {
1534
+
return {&next_, has_next_ ? 1u : 0u};
1535
+
}
1536
+
1537
+
auto get_write_buffer() const -> span<char> { return {nullptr, 0}; }
1538
+
1539
+
auto get() -> int {
1540
+
has_next_ = false;
1541
+
return file_base<F>::get();
1542
+
}
1543
+
1544
+
void unget(char c) {
1545
+
file_base<F>::unget(c);
1546
+
next_ = c;
1547
+
has_next_ = true;
1548
+
}
1549
+
1550
+
void advance_write_buffer(size_t) {}
1551
+
};
1552
+
1553
+
template <typename F, FMT_ENABLE_IF(sizeof(F::_p) != 0)>
1554
+
auto get_file(F* f, int) -> apple_file<F> {
1555
+
return f;
1556
+
}
1557
+
inline auto get_file(FILE* f, ...) -> fallback_file<FILE> { return f; }
1558
+
1559
+
using file_ref = decltype(get_file(static_cast<FILE*>(nullptr), 0));
1560
+
1561
+
class file_print_buffer : public buffer<char> {
1562
+
private:
1563
+
file_ref file_;
1564
+
1565
+
void set_buffer() {
1566
+
file_.advance_write_buffer(size());
1567
+
auto buf = file_.get_write_buffer();
1568
+
this->set(buf.data, buf.size);
1569
+
}
1570
+
1571
+
static void grow(buffer<char>& buf, size_t) {
1572
+
auto& self = static_cast<file_print_buffer&>(buf);
1573
+
self.set_buffer();
1574
+
}
1575
+
1576
+
public:
1577
+
explicit file_print_buffer(FILE* f) : buffer(grow, size_t()), file_(f) {
1578
+
flockfile(f);
1579
+
set_buffer();
1580
+
}
1581
+
~file_print_buffer() {
1582
+
file_.advance_write_buffer(size());
1583
+
funlockfile(file_);
1584
+
}
1585
+
};
1586
+
1435
1587
#if !defined(_WIN32) || defined(FMT_WINDOWS_NO_WCHAR)
1436
1588
FMT_FUNC auto write_console(int, string_view) -> bool { return false; }
1437
1589
#else
@@ -1470,6 +1622,10 @@ FMT_FUNC void print(std::FILE* f, string_view text) {
1470
1622
} // namespace detail
1471
1623
1472
1624
FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) {
1625
+
if (detail::file_ref(f).is_buffered()) {
1626
+
auto&& buffer = detail::file_print_buffer(f);
1627
+
return detail::vformat_to(buffer, fmt, args);
1628
+
}
1473
1629
auto buffer = memory_buffer();
1474
1630
detail::vformat_to(buffer, fmt, args);
1475
1631
detail::print(f, {buffer.data(), buffer.size()});
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4