14 Kasım 2018 Çarşamba

strcspn metodu

Giriş
İkinci parametrenin herhangi bir karakterinin başladığı konumu döner.

Örnek
\r\n veya \n karakterlerinin başladığı konumu bulmak için şöyle yaparız.
fgets(buf, MAX_LINE_LEN, f_input);
buf[strcspn(buf, "\n\r")] = '\0';

gcc extension - __attribute__ packed

Giriş
Açıklaması şöyle.
The packed attribute specifies that a variable or structure field should have the smallest possible alignment—one byte for a variable
Örnek - C++
Şöyle yaparız
struct __attribute__((__packed__)) BitsField 
{
  // Logic values
  uint8_t vesselPresenceSw: 1;
  uint8_t drawerPresenceSw: 1;
  uint8_t pumpState: 1;
  uint8_t waterValveState: 1;
  uint8_t steamValveState: 1;
  uint8_t motorDriverState: 1;
    // Unused
  uint8_t unused_0: 1;
  uint8_t unused_1: 1;
};
Örnek - C
Şöyle yaparız.
struct packet {
  uint16_t mfg;
  uint8_t type;
  uint16_t devid;
} __attribute__((packed));
Örnek - Portable Kod
Şu kullanım sanırım daha portable kod.
#pragma pack(1)
typedef struct {
    unsigned char __reserved : 1;
    unsigned char dont_fragment : 1;
    unsigned char more_fragment : 1;
    unsigned short fragment_offset : 13; 
} ipv4_fragmenting;
#pragma pack()
Örnek - 1 Byte
Açıklaması şöyle
To pack a class is to place its members directly after each other in memory
Şöyle yaparız.
struct Sensor1Telemetry {
  int16_t temperature;
  uint32_t timestamp;
  uint16_t voltageMv;
    // etc...
} __attribute__((__packed__));
Bu kod portable değil. gcc aynı zamanda Microsoft kodlarını da okuyabiliyor. Portable kod için #pragma pack() şeklinde kullanırız.

Örnek - 1 byte
Şöyle yaparız:
#pragma pack(push, 1)
typedef struct {
  unsigned char __reserved : 1;
  unsigned char dont_fragment : 1;
  unsigned char more_fragment : 1;
  unsigned short fragment_offset : 13; 
} ipv4_fragmenting;
#pragma pack(pop)
Şöyle yaparız.
#pragma pack(push, 1)
struct Sensor1Telemetry {
  int16_t temperature;
  uint32_t timestamp;
  uint16_t voltageMv;
  // etc...
};
#pragma pack(pop)

Örnek - 4 byte padding
Şöyle yaparız
#pragma pack(push,4)
struct  MyStruct
{  
    uint32_t i1;        /* offset=0  size=4 */
    uint32_t i2;        /* offset=4  size=4 */
    uint16_t s1;        /* offset=8  size=2 */
    unsigned char c[8]; /* offset=10 size=8 */
    uint16_t s2;        /* offset=18 size=2 */
    uint16_t s3;        /* offset=20 size=2 */
                        /* offset=22 padding=2 (needed to align MyStruct) */
} ; // total size is 24


12 Kasım 2018 Pazartesi

std::optional Sınıfı

Giriş
Bu sınıf C++17 ile standarda girdi. Daha önceki derleyicilerde kullanmak istersek şu satırı dahil ederiz.
#include <experitmental/optional>
Bu sınıfı kullanırken std::nullopt'ye de ihtiyaç oluyor.

C++14 - Tanımlama
Açıklaması şöyle.
Class template optional imposes little requirements on T: it has to be either an lvalue reference type, or a complete object type satisfying the requirements of Destructible.
Örnek - template
Yani sınıf T tipi incomplete olduğu için template içinde kullanılamaz. Şöyle yapamayız.
template <typename T>
struct node {
  std::experimental::optional<node<T>> next;
  T data;
};
Sebebi ise optional içinde T tipinin büyüklüğü kadar bellek alanının ayrılması. Kodu şuna benzer. Eğer T tipi incomplete ise bu kod derlenmez.
template <class T>
struct optional
{
  bool _containsValue;
  char _buffer[ sizeof( T ) ];
};
Ya da kodu şuna benzer. Neticede T tipi için yeterli bellek alanının ayrılması gerekir.
template <typename T>
struct optional
{
    std::aligned_storage_t<sizeof(T), alignof(T)> _data;
    bool _set;
};
Örnek - abstract class
Ku kod derlenmez. Sebebi yine aynı şekilde Type tipini abstract olduğu için büyüklüğünün bilinmemesi.
struct Type {
    virtual bool func(const std::string& val) const noexcept = 0;
}

// in main
optional<Type> = some_function_returning_optional_type();
C++17 - Tanımlama
C++14 ile gelen incomplete type kuralı geçerli değil. Şöyle yaparız.
template<typename T>
auto test()
{
  auto opt = std::optional<T>{T{}};
  ...
}

test<int>();
test<double>();
test<std::string>();
Alignment
Açıklaması şöyle. Yani std::optional T tipinin alignment kurallarına uymalı.
23.6.3 Class template optional
(...) The contained value shall be allocated in a region of the optional storage suitably aligned for the type T.
Constructor
İçinde nesne olmayan optional yaratır.
Örnek
Şöyle yaparız.
std::optional<T> t; // initially empty
Örnek
Şöyle yaparız
optional<Big> ob{emplace, "1"}; // calls Big{"1"} in place (no moving)
optional<Big> oc{emplace};      // calls Big{} in place (no moving)
optional<Big> od{};             // creates a disengaged optional

Örnek
İçinde nesne olmayan optional sınıfına erişmek tanımsız (undefined) davranıştır. Exception fırlatmaz. Şu kod hatalı.
optional<int> t{}; // nullopt (empty) by default
cout << *t << endl;
Constructor - std::in_place + Args
İmzası şöyle
template< class... Args > 
explicit optional( std::in_place_t, Args&&... args );
in_place construction için kullanılır. Şöyle yaparız.
std::optional<std::vector<int>> x{std::in_place, {1,2,3,4,5}}; // OK
Şu kod derlenmiyor ancak ne yapmak lazım bilmiyorum.
std::optional<std::vector<int const>> y{std::in_place, {1,2,3,4,5}}; // error!
Copy Constructor
Açıklaması şöyle
...shall be defined as deleted unless is_copy_constructible_v<T> is true.
Move Constructor
Açıklaması şöyle
...shall not participate in overload resolution unless is_move_constructible_v<T> is true.
Örnek
Şöyle yaparız.
std::optional<X> o1;
std::optional<X> o2(std::move(o1));
Örnek
Move işlemi sonunda primitive tip varsa foo halen dolu görünebilir. Şöyle yaparız.
std::optional<int> foo{ 0 };
std::optional<int> bar{ std::move(foo) };

std::cout << std::boolalpha
          << foo.has_value() << '\n'  // true
          << bar.has_value() << '\n'; // true
emplace metodu
Örnek
Şöyle yaparız.
std::optional<int> x;
x.emplace(3);
Örnek
Şöyle yaparız.
// now we're ready to create the T value
t.emplace(foo, bar); // constructs the T with foo, bar as args
operator* metodu
Adresin hep aynı olup olmaması konusu belirsiz. Şu kod undefined behavior'a sebep olabilir.
template<typename T>
auto test()
{
  auto opt = std::optional<T>{T{}};
  auto* ptr = &*opt;

  opt.reset();
  opt = T{};

  assert(ptr == &*opt); // Can this assert fail?
}
value_or metodu
Örnek
Şöyle yaparız.
template<typename T, typename F>
T lazy_value_or(const std::optional<T> &opt, F fn) {
    if(opt) return opt.value();
    return fn();
}
Örnek
Şöyle yaparız.
template <typename F>
struct Lazy
{
  F f;  

  operator decltype(f())() const
  {
    return f();
  }
};

template <typename F>
Lazy(F f) -> Lazy<F>;

int main()
{
  std::optional<int> o;

  int i = o.value_or(Lazy{[]{return 0;}});
}

Diğer seçenekler
Eğer elimizde std::optional yoksa, ve boost::optional kullanmak istemiyorsak şöyle yapabiliriz.

1. unique_ptr kullanabiliriz.
Şöyle yaparız.
std::unique_ptr<double> possiblyFailingCalculation();
std::unique_ptr kendi içine null kontrolü yaptığı için kolaylıkla kullanılabilir.

2. std::pair kullanılabilir.
Örnek
Şöyle yaparız.
std::pair<double,bool> possiblyFailingCalculation();
Örnek
Şöyle yaparız.
using std_optional_int = std::optional<int>;
using my_optional_int = std::pair<int, bool>;

3. Eski usul kodlarız.
Şöyle yaparız.
bool possiblyFailingCalculation(double& output);