Skip to content

Instantly share code, notes, and snippets.

@Stanley00
Last active January 15, 2024 10:26
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 Stanley00/ef8151502a93deefe4fa to your computer and use it in GitHub Desktop.
Save Stanley00/ef8151502a93deefe4fa to your computer and use it in GitHub Desktop.
C++ small code snip
#include <stdio.h>
#include <stdlib.h>
#define DECLARE(...) for(__VA_ARGS__
#define DECLARE_CHECK(...) __VA_ARGS__
#define DEFER(...) __VA_ARGS__)
#define DEFER_BREAK continue
int main(void)
{
DECLARE(int *p) = malloc(10*sizeof(*p));
DECLARE_CHECK(p);
DEFER(free(p), p=NULL, printf("Free p\n")){
DECLARE(int *q)=malloc(10*sizeof(*q));
DECLARE_CHECK(q);
DEFER(free(q), q=NULL, printf("Free q\n")){
printf("Yay\n");
DEFER_BREAK;
printf("No\n");
}
printf("Yuck\n");
}
return EXIT_SUCCESS;
}
#include <stdio.h>
struct range
{
int from;
int to;
int step;
};
#define range(...) range((struct range){.from=1,.to=10,.step=1, __VA_ARGS__})
int sign(int n)
{
if (n<0)
{
return -1;
}
return 1;
}
/* use parentheses to avoid macro subst */
void (range)(struct range r)
{
int i;
if ((r.to-r.from)*r.step<0)
{
r.step*=-1;
}
for (i = r.from; i*sign(r.step) <= r.to*sign(r.step); i += r.step)
{
printf("%d ", i);
}
puts("");
}
int main()
{
range();
range(.from=2, .to=4);
range(.from=10, .to=2);
range(.step=2);
return 0;
}
size_t count_utf8_char(const std::string& s)
{
size_t count = 0;
for (const unsigned char p : s)
{
if ( (p&0x80)==0 || (p&0xc0)==0xc0)
count++;
}
return count;
}
#include <iostream>
using namespace std;
#define BARK std::cout << __PRETTY_FUNCTION__ << '\n'
template <class Z, class X>
struct Y
{
auto operator ->() const
{
return &z;
}
auto operator ->()
{
return &z;
}
private:
~Y() = default;
friend X;
Z z;
};
struct Z
{
void f()
{
BARK;
}
};
struct X
{
auto& get()
{
return y;
}
private:
Y<Z, X> y;
};
int main()
{
X x;
x.get()->f();
//auto y = x.get(); // error
}
#include <iostream>
// This cannot be used for rvalue array
// And make sure you pass const ref to both functions
template <typename T, size_t N> constexpr size_t count_of (const T (&a)[N]){return N;}
template <typename T, size_t N> constexpr size_t test(const T (&a)[N]){ return count_of(a);}
int main()
{
int a[]={1,2,3,4,5};
int b[]={1,2,3,4,5,6,7,8};
// Should output: 5 8
std::cout << test(a) << "\n" << test(b) << "\n";
return 0;
}
#include <iostream>
#include <functional>
#include <optional>
#define BARK do {std::cout << __PRETTY_FUNCTION__ << '\n';} while(0)
void f(){
BARK;
}
using Callback = void (*)(void);
auto call(Callback f){
return f();
}
void g(int i){
std::cout << i << " from "; BARK;
}
template<auto cb, class... Ts>
constexpr auto make_void_cb(Ts&&... ds){
static std::optional<std::tuple<Ts...>> d;
if (d) throw d;
d = std::make_tuple(std::forward<Ts>(ds)...);
struct XX{
static void f(){
std::apply(cb, *d);
d = std::nullopt;
}
};
return &XX::f;
}
int main()
{
call(f);
call(make_void_cb<g>(42));
call(make_void_cb<g>(47));
}
#include <iostream>
#include <iomanip>
#include <vector>
constexpr auto POW(unsigned long long base, unsigned exp){
auto r = base;
while(--exp){
r *= base;
}
return r;
}
struct BigNum{
BigNum(unsigned long long n): data_{{n}}{}
bool operator<(const BigNum& o) const{
if (data_.size()<o.data_.size()) return true;
if (data_.size()>o.data_.size()) return false;
for (auto li=data_.rbegin(), ri=o.data_.rbegin(); li!=data_.rend(); ++li, ++ri){
if (*li < *ri) return true;
if (*li > *ri) return false;
}
return false;
}
auto operator[](size_t i) const {
return (i<data_.size())?data_[i]:0;
}
BigNum& operator+=(const BigNum& o){
unsigned long long carry = 0;
const auto max_len = std::max(data_.size(), o.data_.size());
for (size_t i=0; i<max_len; ++i){
data_[i] = (*this)[i] + o[i] + carry;
carry = data_[i]/BASE;
data_[i] %= BASE;
}
while (carry>0){
data_.push_back(carry%BASE);
carry /= BASE;
}
return *this;
}
BigNum& operator*=(unsigned long long n){
unsigned long long carry = 0;
for (size_t i=0; i<data_.size(); ++i){
data_[i] = (*this)[i]*n+carry;
carry = data_[i]/BASE;
data_[i] %= BASE;
}
while (carry>0){
data_.push_back(carry%BASE);
carry /= BASE;
}
return *this;
}
private:
static constexpr unsigned BASE_WIDTH = 9;
static constexpr unsigned long long BASE = POW(10, BASE_WIDTH);
std::vector<unsigned long long> data_;
friend decltype(auto) operator<<(std::ostream&, const BigNum&);
};
decltype(auto) operator<<(std::ostream& os, const BigNum& n){
os << *rbegin(n.data_);
for (auto i=next(rbegin(n.data_)); i<rend(n.data_); ++i)
os << std::setfill('0') << std::setw(n.BASE_WIDTH) << *i;
return os;
}
int main()
{
BigNum n = 1;
for (int i=1; i<100; ++i){
n*=i;
std::cout << n << '\n';
}
n += n;
std::cout << n;
}
// Idea got from https://verdagon.dev/blog/on-removing-let-let-mut
// Require C++17
#include <iostream>
template<class T>
struct let_assign;
template<class T>
struct let{
let(const T& a):d{a}{}
template<class X>
let& operator=(X&&){
static_assert(sizeof(X)==0, "Must use let_assign to assign"); return *this;
}
operator const T&() const{
return d;
}
friend struct let_assign<T>;
private:
T d={};
};
template<class T>
struct let_assign{
let_assign(let<T>& x):x{x}{};
decltype(auto) operator=(int a){
x.d = a;
return *this;
}
private:
let<T>& x;
};
template<class T>
let_assign(let<T>&) -> let_assign<T>;
int main() {
let x = 10;
//x = 20; // Error, must use `let_assign` "keyword"
let_assign {x} = 42;
std::cout << x << '\n';
}
template <class>
struct Succ;
struct Zero;
template<unsigned>
struct Num_;
template<unsigned n>
using Num = Num_<n>::val;
template<>
struct Num_<0>{
using val = Zero;
};
template<unsigned n>
struct Num_{
using val = Succ<Num<n-1>>;
};
template <class, class>
struct Add_;
template <class U, class V>
using Add = typename Add_<U, V>::type;
template <class T>
struct Add_<Zero, T>{
using type = T;
};
template <class T, class U>
struct Add_<Succ<T>, U>{
using type = Succ<Add<T, U>>;
};
template <class>
constexpr bool always_false = false;
template <class T, class>
struct Same{
static_assert(always_false<T>, "Proof failed");
};
template<class T>
struct Same<T, T>{};
using Four = Num<4>;
using Two = Num<2>;
constexpr auto Proof = Same<Add<Two, Two>, Four>{};
#include <vector>
#include <array>
#include <stdexcept>
namespace nonstd
{
template <class T, size_t Size>
struct StackAllocator {
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using propagate_on_container_move_assignment = std::false_type;
using is_always_equal = std::false_type;
[[nodiscard]] T* allocate(std::size_t n)
{
if ((n > Size) || (c_[1] > 0)) {
throw std::bad_alloc();
}
if (c_[0]==0) {
c_[0] = n;
} else {
c_[1] = n;
}
return &m_[0];
}
size_type max_size() const
{
return Size;
}
void deallocate(T*, std::size_t n) noexcept
{
if (n==c_[0]) {
c_[0] = c_[1];
c_[1] = 0;
}
}
private:
std::array<T, Size> m_;
size_type c_[2] = {};
};
template <class T, class U, std::size_t SizeT, std::size_t SizeU>
bool operator==(const StackAllocator<T, SizeT>& t, const StackAllocator<U, SizeU>& u)
{
return &t == &u;
}
template <class T, class U, std::size_t SizeT, std::size_t SizeU>
bool operator!=(const StackAllocator<T, SizeT>& t, const StackAllocator<U, SizeU>& u)
{
return !(t==u);
}
template<class T, std::size_t Size>
using stack_vector = std::vector<T, StackAllocator<T, Size>>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment