RB-tree в sglib

Наткнулся на довольно мерзкий баг, в когда-то уважаемой мной библиотеке sglib. Дело в том, что на определенных наборах данных у rb-tree из этой библиотеки сносит башню! В результате добавленные ранее элементы перестают находиться, хотя, количество элементов не изменяется и при обходе дерева все элементы в нем присутствуют.

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include "sglib.h"

struct rb_tree
{
    int64_t data;
    char color_field;
    struct rb_tree *left;
    struct rb_tree *right;
};
typedef struct rb_tree rb_tree;

#define CMPARATOR(x,y) ((x->data)-(y->data))

SGLIB_DEFINE_RBTREE_PROTOTYPES(rb_tree, left, right, color_field, CMPARATOR);
SGLIB_DEFINE_RBTREE_FUNCTIONS(rb_tree, left, right, color_field, CMPARATOR);

rb_tree *the_tree = 0;

int main(int argc, char *argv[])
{
    if( argc < 2 )
        return -1;

    const char *data_file_path = argv[1];
    FILE *data_file;
    data_file = fopen( data_file_path, "r" );
    if( 0 == data_file )
        return -1;

    uint64_t value;
    rb_tree *node, e;
    e.data = 6610223104;
    int added = 0;
    while( EOF != fscanf( data_file, "%llun", &value ) )
    {
        if( value == e.data )
            added = 1;
        node = malloc( sizeof(rb_tree) );
        node->data = value;
        sglib_rb_tree_add( &the_tree, node );
        if( 0 != added )
        {
            node = sglib_rb_tree_find_member( the_tree, &e );
            if( 0 == node )
                printf("ERRORn");
        }
    }

    return 0;
}

Файл с тестовыми данными.

Классическая задача для собеседования в реальной жизни

Случилось странное – я столкнулся с буквально классической задачей с собеседования в реальной жизни. Задача состоит в том, что необходимо найти первый не нулевой бит в массиве. Поиск должен происходить максимально быстро, скорость поиска желательно получить приближённую к линейной. Никаких правил по распределению единиц в массиве нет. Массив не велик и должен не вылезать за пределы одной кэш-линии.
Родились 3 варианта алгоритма, одна часть которого общая во всех случаях, вторая специфическая.
Общая часть сводится к поиску первого 32 разрядного слова с хотя бы одним не нулевым битом. Дальше, в найденном 32 разрядном слове ищем первый не нулевой бит. Я не знаю как можно оптимизировать первую часть алгоритма, так что ищу простым перебором. Continue reading

Управление памятью в ANSI C

Довольно занятная ситуация: чем больше я пишу кода, тем более простой код мне нравится писать. Что интересно, наиболее простой код выходит не на C++ или Objective-C и даже не на Python, а на чистом C. Хотя, оно и понятно, нет тут простора для творчества
А вот в самом C есть один основательно напрягающий меня момент: освобождение памяти. Довольно часто приходится работать со структурами, в состав которых входят массивы, строки переменной длинны или массивы структур со всей этой радостью одновременно. А раз уж от создания такой конструкции никуда не денешься, то как минимум хочется иметь возможность ее легко удалить.
Подход с использование garbage collector мне не очень нравится, все же это как из пушки по воробьям… А вот построение из выделяемой памяти подобия дерева, мне показалось куда более интересным.
Continue reading

Undefined Behavior для C разработчиков

Очень интересная серия статей посвященных Undefined Behavior от Криса Чембера, одного из авторов LLVM.
What Every C Programmer Should Know About Undefined Behavior #1/3
What Every C Programmer Should Know About Undefined Behavior #2/3
What Every C Programmer Should Know About Undefined Behavior #3/3

Квалификатор restraint

Последнее время я довольно много пишу на Си, да чистое Си, без никаких плюсов, обджектив и прочей радости. На первый взгляд, в Си все очень и очень просто. Но, как оказалось, это только кажется, на том же BrainBench в тесте по Си мне удалось набрать всего 3.25, против 4.34 по плюсам. А еще говорят что BB ни о чем не говорит, говорит и еще как
А вступление это вот к чему. Я решил написать небольшую серию заметок про Си, если говорить точнее, то про C99. Ведь лучший способ что-то запомнить – это написать.
В состав C99 был добавлен новый квалификатор типа – restraint.
Данный квалификатор используется применительно к указателям и говорит компилятору о том, что данные, на которые указывают такие указатели, не являются пересекающимися объектами. Чисто теоретически, подобная информаия позволяет компилятору произвести дополнительные виды оптимизации. Теоретически, т.к. покрутив этот квалификатор и так и сяк я не сумел заставить компилятор хоть как-то изменить генерируемый код.
Основные варианты использования квалификатора restraint:

Continue reading