<|start_filename|>temp/tistr.c<|end_filename|>
#include <stdlib.h>
#include <string.h>
#include "tistr.h"
/*
 * @desc : 初始化tistr struct结构体
 * @param : 来源二进制buf
 */
tistr_struct * tistr_init(char * buf)
{
    // 初始化各种变量
    size_t buf_length;
    tistr_struct * tistr_struct_p
    // 一、初始化好tistr_struct
    tistr_struct_p = (tistr_struct *)malloc(sizeof(tistr_struct));
    // 二、注意：初始化了tistr_struct但是并没有为其中的buf成员分配内存
    // sizeof并不记录末尾null也就是空字节的长度
    buf_length = sizeof(buf);
    tistr_struct_p->length = 0;
    tistr_struct_p->free   = buf_length;
    tistr_struct_p->buf    = (char *)malloc(buf_length + 1);
    // 三、拼接字符串
    tistr_strcat(tistr_struct_p, buf);
    return tistr_struct_p;
}

/*
 * @desc : 将二进制字符们复制到tistr结构中去
 * */
void tistr_strcat(tistr_struct * tistr_struct_pointer, char * source_buf)
{
    // 初始化各种变量
    size_t buf_length;
    char * new_buf;
    char * old_buf;
    // 一、根据tistr-struct结构体free判断空间是否足够分配
    buf_length = sizeof(source_buf);
    if (tistr_struct_pointer->free >= buf_length) {
        tistr_struct_pointer->free   = tistr_struct_pointer->free - buf_length;
        tistr_struct_pointer->length = tistr_struct_pointer->length + buf_length;
        strcat(tistr_struct_pointer->buf, source_buf);
    // 二、如果tistr-struct中空间不足以放下buf，就涉及到扩容了
    } else {
        new_buf = tistr_expansion(tistr_struct_pointer, buf_length);
        strcpy(new_buf, tistr_struct_pointer->buf);
        strcat(new_buf, source_buf);
        // 释放之前旧的buf内存
        old_buf = tistr_struct_pointer->buf;
        free(old_buf);
        // 走上新开辟的大buf
        tistr_struct_pointer->buf = new_buf;
    }
}

/*
 * @desc : 将字符们复制到tistr结构中去
 * */
void tistr_strcpy(tistr_struct * tistr_struct_pointer, char * source_buf)
{
    //初始化各种变量
    size_t source_buf_length;
    char * new_buf;
    char * old_buf;
    // 一、根据tistr-struct结构体free判断空间是否足够分配
    source_buf_length = sizeof(source_buf);
    // 空间刚好够用.
    if ((tistr_struct_pointer->free + tistr_struct_pointer->length) >= source_buf_length) {
        memset(tistr_struct_pointer->buf, '\0', tistr_struct_pointer->free + tistr_struct_pointer->length);
        strcpy(tistr_struct_pointer->buf, source_buf);
        tistr_struct_pointer->length = source_buf_length;
        tistr_struct_pointer->free   = 0;
    } else {
        new_buf = tistr_expansion(tistr_struct_pointer, source_buf_length);
        strcpy(new_buf, source_buf);
        // 释放之前旧的buf内存
        old_buf = tistr_struct_pointer->buf;
        free(old_buf);
        // 走上新开辟的大buf
        tistr_struct_pointer->buf = new_buf;
    }
}

/*
 * @desc : 扩容算法
 * */
char * tistr_expansion(tistr_struct * tistr_struct_pointer, size_t buf_length)
{
    char * new_buf;
    size_t new_length;
    size_t new_free;
    //1048576B = 1MB
    new_length = tistr_struct_pointer->length + buf_length;
    // new_length小于等于1MB
    // new_length大于1MB
    new_buff = tistr_struct_pointer->length + buf_length <= 1048576 ? new_length : 1048576 ;
    char * new_buf = (char *)malloc(new_length + new_free + 1);
    tistr_struct_pointer->length = new_length;
    tistr_struct_pointer->free   = new_free;
    return new_buf;
}

/*
 * @desc : 获取已占用长度（不包括末尾\0）
 * */
size_t tistr_get_length(tistr_struct * tistr_struct_pointer)
{
    return tistr_struct_pointer->length;
}

/*
 * @desc : 获取剩余可用长度
 * */
size_t tistr_get_free(tistr_struct * tistr_struct_pointer)
{
    return tistr_struct_pointer->free;
}

/*
 * @desc : 清空一个tistr结构体，并且释放内存空间
 */
void tistr_truncate(tistr_struct * tistr_struct_pointer)
{
    free(tistr_struct_pointer->buf);
    tistr_struct_pointer->length = 0;
    tistr_struct_pointer->free   = 0;
    free(tistr_struct_pointer);
}

/*
 * @desc : 清空一个tistr结构体的buf，但不释放空间
 */
void tistr_empty(tistr_struct * tistr_struct_pointer)
{
    tistr_struct_pointer->length = 0;
    tistr_struct_pointer->free   = 0;
    free(tistr_struct_pointer->buf);
}

<|start_filename|>config.h<|end_filename|>
#ifndef __CONFIG_H
#define __CONFIG_H

// linux
#if __linux__
  #define IS_EPOLL 1
#endif
// unix:openbsd freebsd
#if __unix__
#endif

#endif


<|start_filename|>datastructure/string.c<|end_filename|>
#include <stdlib.h>
#include "sds.h"
/*
 * @desc : init an empty sds struct
 */
sds_struct * sds_init( char * buf ) {
}
/*
 * @desc : empty sds buf
 */
void sds_empty( sds_struct * sds_struct_pointer ) {
    free( sds_struct_pointer->buf );
    sds_struct_pointer->length = 0;
}

void sds_strcat( char * dest, char * source ) {
}

void sds_strcpy( char * dest, char * source ) {
}

size_t sds_get_length( sds_struct * sds_struct_pointer ) {
    return sds_struct_pointer->length;
}

size_t sds_get_free( sds_struct * sds_struct_pointer ) {
    return sds_struct_pointer->free;
}


<|start_filename|>Makefile<|end_filename|>
objects = main.o event/ev_factory.o protocol/protocol.o datastructure/hashtable.o
tidis : $(objects)
	gcc -o tidis $(objects)
main.o : main.c
	gcc -c main.c
ev_factory.o : ev_factory.c 
	gcc -c event/ev_factory.c
prootocol.o : prootocol.c
	gcc -c prootocol/prootocol.c
hashtable.o : hashtable.c
	gcc -c datastructure/hashtable.c
.PHONY : clean
clean :
	-rm $(objects)
#main.o : main.c defs.h
#    cc -c main.c


<|start_filename|>protocol/protocol.h<|end_filename|>
#define TIP_LINE_MAX_LEN 1024

#define TIP_OBJECT_ARRAY  1
#define TIP_OBJECT_STRING 2
#define TIP_OBJECT_INT    3

/*
 * @desc : protocol parser
 * */
typedef struct command_cell_struct {
    int type;      // command cell type
    int length;    // command cell length
    int interger;  //
    unsigned int  string_length;   // bulk string length
    unsigned char * string;        // bulk string
    unsigned int  cell_length;
    struct command_cell_struct ** cell; // next command cell part
} command_cell_struct;

// function prototpye
int decode_command( command_cell_struct **, char * );              // encode whole command
void encode_command();                            // decode whole command
command_cell_struct * create_command_cell();      // create a command_cell_struct
void free_command_cell( command_cell_struct * );  // release useless memory
int string2int( const unsigned char * );         // convert string 2 int
char * int2string();                             // convert int 2 string
int process_offset( const unsigned char * );     // calculate offset \r\n
command_cell_struct * create_command_array( unsigned int );
command_cell_struct * create_command_string( const unsigned char *, unsigned int, unsigned int );

<|start_filename|>temp/tilink.c<|end_filename|>
#include <stdlib.h>
#include <string.h>
#include "tilink.h"

/*
 * @desc : 初始化一个空的link-entry，里边一个node都没有
 * */
tilink_entry_struct * link_init()
{
    tilink_entry_struct * tilink_entry_struct_point;
    tilink_entry_struct_point = (tilink_entry_struct *)malloc(sizeof(tilink_entry_struct));
    tilink_entry_struct_point->length = 0;
    tilink_entry_struct_point->head   = NULL;
    tilink_entry_struct_point->tail   = NULL;
    return tilink_entry_struct_point;
}

/*
 * @desc : 创建一个node，并赋值value
 * */
tilink_node_struct * node_init()
{
    tilink_node_struct * tilink_node_struct_point;
    tilink_node_struct_point = (tilink_node_struct *)malloc(sizeof(tilink_node_struct));
    return tilink_node_struct_point;
}

/*
 * @desc : 将node追加到head
 * */
void * add_head(tilink_entry_struct * tilink_entry_point, tilink_node_struct * new_node)
{
    if (0 == tilink_entry_point->length) {
        tilink_entry_point->tail = new_node;
        tilink_entry_point->head = new_node;
        tilink_entry_point->length++;
    } else {
        tilink_node_struct * head_node;
        head_node = tilink_entry_point->head;
        new_node->next = head_node;
        tilink_entry_point->head = new_node;
        tilink_entry_point->length++;
    }
}

/*
 * @desc : 将node追加到tail
 * */
void * add_tail(tilink_entry_struct * tilink_entry_point, tilink_node_struct * new_node)
{
    if (0 == tilink_entry_point->length) {
        tilink_entry_point->tail = new_node;
        tilink_entry_point->head = new_node;
        tilink_entry_point->length++;
    } else {
        tilink_node_struct * tail_node;
        tail_node = tilink_entry_point->tail;
        new_node->prev = tail_node;
        tilink_entry_point->tail = new_node;
        tilink_entry_point->length++;
    }
}

/*
 * @desc : 根据index获取node, O(N)
 * */
tilink_node_struct * get_node_by_index(tilink_entry_struct * tilink_entry_point, unsigned long index)
{
    tilink_node_struct * node;
    unsigned long pos = 1;
    unsigned long length;
    length = get_link_length(tilink_entry_point);
    // 验证下长度
    if (index > length) {
        return NULL;
    }
    node = tilink_entry_point->head;
    while(pos < index) {
        node = node->next;
        pos++;
    }
    return node;
}

/*
 * @desc : 根据value获取node
 * */
tilink_node_struct * get_node_by_value(tilink_entry_struct * tilink_entry_point, void * value)
{
    tilink_node_struct * node;
    tilink_iterator_struct iterator;
    reset_link_2_head(tilink_entry_point, &iterator);
    // 开始遍历整个link，与value数值进行对比
    while((node = link_next(&iterator)) != NULL) {
        if (value == node->value) {
            return node;
        }
    }
    return NULL;
}

/*
 * @desc : 一般用于while不断next
 * */
tilink_node_struct * link_next(tilink_iterator_struct * tilink_iterator_point)
{
    tilink_node_struct * current_node;
    current_node = tilink_iterator_point->next;
    if (current_node != NULL) {
        if (ITERATOR_TAIL_TO_HEAD == tilink_iterator_point->direction)
            tilink_iterator_point->next = current_node->next;
        else
            tilink_iterator_point->next = current_node->prev;
    }
    return current_node;
}

/*
 * @desc : rewind link-list到head处
 * */
void reset_link_2_head(tilink_entry_struct * tilink_entry_point, tilink_iterator_struct * tilink_iterator_point)
{
    tilink_iterator_point->next      = tilink_entry_point->head;
    tilink_iterator_point->direction = 0;
}

/*
 * @desc : 返回头部node
 * */
tilink_node_struct * get_link_head(tilink_entry_struct * tilink_entry_point)
{
    return tilink_entry_point->head;
}

/*
 * @desc : 返回尾巴node
 * */
tilink_node_struct * get_link_tail(tilink_entry_struct * tilink_entry_point)
{
    return tilink_entry_point->tail;
}

/*
 * @desc : 获取link长度
 * */
unsigned long get_link_length(tilink_entry_struct * tilink_entry_point)
{
    return tilink_entry_point->length;
}

<|start_filename|>datastructure/object.h<|end_filename|>
#ifndef __TIDIS_OBJECT_H
#define __TIDIS_OBJECT_H

// tidis object struct
typedef struct tidis_object_struct {
    int type;    // 类型，目前只有字符串.
    void * ptr;  // 指向的数据指针
} tidis_object_struct;

#endif

<|start_filename|>datastructure/hashtable.c<|end_filename|>
#include "hashtable.h"

/*
 * @desc : init the hashtable entry
 */
ht_st * init_ht() {
    ht_st * ht_entry;
    ht_entry = ( ht_st * )malloc( sizeof( ht_st ) );
    ht_entry->size = HT_SIZE;
    ht_entry->used = 0;
    //ht_entry->entry = ( ht_node_st * )calloc( ht_entry->size, sizeof( ht_node_st * ) );
    ht_entry->entry = calloc( ht_entry->size, sizeof( ht_node_st * ) );
    return ht_entry;
}

/*
 * @desc : allocate memory for new ht-node
 */
ht_node_st * allocate_ht_node( char * key, void * value ) {
    ht_node_st * ht_node;
    ht_node = ( ht_node_st * )malloc( sizeof( ht_node_st ) );
    ht_node->key   = strdup( key );
    //ht_node->value = strdup( value );
    ht_node->value = value;
    ht_node->next  = NULL;
    return ht_node;
}

/*
 * @desc : destroy a hashtable
 */
void destroy_ht( ht_st * ht_entry ) {
    // 1.destroy ht_entry->entry
    for ( int i = 0; i < ht_entry->size; i++ ) {
        ht_node_st * ht_node = ht_entry->entry[ i ];
        if ( NULL != ht_node ) {
            printf( "destroy node | bingo : %d\n", i );
            destroy_ht_node( ht_node );
        }
        else {
            printf( "destroy node | null\n" );
        }
    }
    // 2.destroy ht_entry
    free( ht_entry->entry );
    free( ht_entry );
}

/*
 * @desc : destroy a hashtable node
 */
void destroy_ht_node( ht_node_st * ht_node ) {
    ht_node_st * temp_ht_node;
    while ( ht_node ) {
        temp_ht_node = ht_node;
        ht_node = ht_node->next;
        free( temp_ht_node->key );
        free( temp_ht_node->value );
        free( temp_ht_node );
    }
}

/*
 * @desc : add a new node to hash-table
 * 当前key，实际上写死为TIDIS_OBJECT_STRING
 */
int add_ht_node( ht_st * ht_entry, tidis_object_struct * tidis_object_key, void * value ) {
    ht_node_st * new_ht_node;
    ht_node_st * origin_ht_node;
    int          hash_index;
    char * key = tidis_object_key->ptr;
    hash_index = hash( key, strlen( key ), 0 ) % HT_SIZE;
    // if hash-collision
    origin_ht_node = ht_entry->entry[ hash_index ];
    if ( origin_ht_node ) {
        // zip method
        printf( "当前位置有节点\n" );
        while ( origin_ht_node ) {
            if ( NULL == origin_ht_node->next ) {
                new_ht_node = allocate_ht_node( key, value );
                origin_ht_node->next = new_ht_node;
                break;
            }
            else {
                origin_ht_node = origin_ht_node->next;
            }
        }
    }
    else {
        printf( "当前位置没有节点，第一次\n" );
        new_ht_node = allocate_ht_node( key, value );
        ht_entry->entry[ hash_index ] = new_ht_node;
    }
    return hash_index;
}

/*
 * @desc : find a key from hash-table
 */
ht_node_st * get_ht_node( ht_st * ht_entry, tidis_object_struct * tidis_object_key ) {
    int hash_index;
    ht_node_st * ht_node;
    char * key = tidis_object_key->ptr;
    hash_index = hash( key, strlen( key ), 0 ) % HT_SIZE;
    ht_node    = ht_entry->entry[ hash_index ];
    // exists hashtable_node @ hash_index
    if ( ht_node ) {
        while ( ht_node ) {
            printf( "get_ht_node\n" );
            if ( 0 == strcmp( key, ht_node->key ) ) {
                break;
            }
            else {
                ht_node = ht_node->next;
            }
        }
        return ht_node;
    }
        // if not exists @ hash_index, return NULL
    else {
        return NULL;
    }
}

/*
 * @desc : look up a key from a zip...
 */
ht_node_st * lookup( ht_node_st * ht_node, const char * key ) {
    if ( NULL == ht_node ) {
        return NULL;
    }
    while ( ht_node ) {
        if ( 0 == strcmp( key, ht_node->key ) ) {
            break;
        }
        else {
            ht_node = ht_node->next;
        }
    }
    return ht_node;
}

/*
 * @desc : delete a key from hashtable
 */
int delete_ht_node( ht_st * ht_entry, const char * key ) {
    int          hash_index;
    int          ret_index = 0;
    int          counter   = 0;
    ht_node_st * entry_ht_node;
    ht_node_st * followup_ht_node;
    hash_index   = hash( key, strlen( key ), 0 ) % HT_SIZE;

    entry_ht_node = ht_entry->entry[ hash_index ];
    // if there node @ temporary index
    if ( NULL == entry_ht_node ) {
        ret_index = 0;
    }
        // exists a node @ index
    else {
        ht_node_st * temp_node;
        temp_node = entry_ht_node;
        // while寻找到这个key
        while ( entry_ht_node ) {
            if ( 0 == strcmp( entry_ht_node->key, key ) ) {
                // first node bingo
                if ( 0 == counter ) {
                    ht_entry->entry[ hash_index ] = NULL;
                }
                    // follow-up node bingo
                else {
                    if ( NULL == entry_ht_node->next ) {
                        temp_node->next = NULL;
                    }
                    else {
                        //printf( "%s %s %s\n", temp_node->key, entry_ht_node->key, entry_ht_node->next->key );
                        //printf( "%p %p\n", temp_node->next, entry_ht_node->next );
                        temp_node->next = entry_ht_node->next;
                    }
                }
                free( entry_ht_node->key );
                free( entry_ht_node->value );
                free( entry_ht_node );
                break;
            }
            else {
                temp_node     = entry_ht_node;
                entry_ht_node = entry_ht_node->next;
                counter++;
            }
        }
    }

    return ret_index;
}

/*
 * @desc : hash function based on murmurhash3
 *         copy from https://github.com/jwerle/murmurhash.c/blob/master/murmurhash.c
 */
uint32_t hash ( const char *key, uint32_t len, uint32_t seed ) {
    uint32_t c1 = 0xcc9e2d51;
    uint32_t c2 = 0x1b873593;
    uint32_t r1 = 15;
    uint32_t r2 = 13;
    uint32_t m  = 5;
    uint32_t n  = 0xe6546b64;
    uint32_t h  = 0;
    uint32_t k  = 0;
    uint8_t *d  = (uint8_t *) key; // 32 bit extract from `key'
    const uint32_t *chunks = NULL;
    const uint8_t *tail    = NULL; // tail - last 8 bytes
    int i  = 0;
    int l  = len / 4; // chunk length
    h      = seed;
    chunks = (const uint32_t *) (d + l * 4); // body
    tail   = (const uint8_t *) (d + l * 4); // last 8 byte chunk of `key'
    // for each 4 byte chunk of `key'
    for (i = -l; i != 0; ++i) {
        // next 4 byte chunk of `key'
        k = chunks[i];
        // encode next 4 byte chunk of `key'
        k *= c1;
        k = (k << r1) | (k >> (32 - r1));
        k *= c2;
        // append to hash
        h ^= k;
        h = (h << r2) | (h >> (32 - r2));
        h = h * m + n;
    }
    k = 0;
    // remainder
    switch (len & 3) { // `len % 4'
        case 3: k ^= (tail[2] << 16);
        case 2: k ^= (tail[1] << 8);
        case 1:
            k ^= tail[0];
            k *= c1;
            k = (k << r1) | (k >> (32 - r1));
            k *= c2;
            h ^= k;
    }
    h ^= len;
    h ^= (h >> 16);
    h *= 0x85ebca6b;
    h ^= (h >> 13);
    h *= 0xc2b2ae35;
    h ^= (h >> 16);
    return h;
}


<|start_filename|>main.h<|end_filename|>
#ifndef __TIDIS_H
#define __TIDIS_H

#define TIDIS_OBJECT_STRING 1

#include "config.h"
// event loop
#include "event/ev_factory.h"
// data structure
#include "datastructure/string.h"
#include "datastructure/hashtable.h"
// command protocol parser
#include "protocol/protocol.h"

// server config struct
// I prefer char array other than char * in struct
// main.c
typedef struct server_config_struct {
    char host[ 32 ];
    char port[ 8 ];
    char event[ 8 ];
    char daemonize[ 4 ];
} server_config_struct;
typedef struct config_item {
    char key[ 16 ];
    char value[ 32 ];
} config_item_struct;

// database struct
typedef struct db_struct {
    // 键key的空间，一个hashtable数据结构
    ht_st * key;
    // 过期时间key的空间，另一个hashtable数据结构
    ht_st * expire;  // 暂时无用
} db_struct;

// client struct
typedef struct client_struct {
    int fd;
    struct sds_struct * io_buffer; // input buffer, data from client to server
} client_struct;

// server struct in main.c
typedef struct server_struct {
    server_config_struct * config;
    int listen_socket_fd;
    db_struct * db;  // 指向数据库的指针
    // client link list
    int db_num;  // 数据库数量.暂时无用，保留
} server_struct;

// main.c : function prototype
server_config_struct * parse_config_file();
server_struct        * init_server( server_config_struct *, ev_loop_struct * );
void net_accept_tcp_connect_processor( ev_loop_struct *, int );
void read_from_client( ev_loop_struct *, int );
bool daemonize();
void net_set_nonblock( int );

// function.c
void ltrim( char * );
void rtrim( char * );
void trim( char * );

#endif

<|start_filename|>datastructure/hashtable.h<|end_filename|>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include "object.h"

#define HT_SIZE 1024

// hashtable node struct
typedef struct hashtable_node {
    char * key;
    void * value;   // 可能会指向任何类型，string、hashtable、list、set、zset等
    struct hashtable_node * next;  //为拉链法解决hash collision
} ht_node_st;

// hashtable entry
typedef struct hashtable_entry {
    size_t size;
    size_t used;
    ht_node_st ** entry;
} ht_st;

// function prototype
// init a hashtable
ht_st * init_ht();
// create a new hashtable node
ht_node_st * allocate_ht_node( char *, void * );
// destroy a hashtable
void destroy_ht( ht_st * );
// destroy a hashtable node
void destroy_ht_node( ht_node_st * );
// get a key
ht_node_st * get_ht_node( ht_st *, tidis_object_struct * tidis_object_key );
// insert a key
int add_ht_node( ht_st *, tidis_object_struct *, void * );
// delete a key
int delete_ht_node( ht_st *, const char * );
// hash algorithm based on murmurhash3
uint32_t hash( const char *, uint32_t, uint32_t );


<|start_filename|>event/epoll.c<|end_filename|>
#include <sys/epoll.h>

/*
 * @desc : fd for select API
 */
typedef struct ev_fd_entry_struct {
    struct epoll_event * events;
    int    epoll_fd;
} ev_fd_entry_struct;

/*
 * @desc : create epoll event for ev_fd_entry_struct
 */
static void ev_create_fd_entry( ev_loop_struct * ev_loop ) {
    int epoll_fd = 0;
    ev_fd_entry_struct * fd_entry = ( ev_fd_entry_struct * )malloc( sizeof( ev_fd_entry_struct ) );
    struct epoll_event events[ ev_loop->event_size ];
    fd_entry->events = events;
    epoll_fd = epoll_create( ev_loop->event_size );
    if ( epoll_fd < 0 ) {
        return;
    }
    fd_entry->epoll_fd = epoll_fd;
    ev_loop->fd_entry  = fd_entry;
}

/*
 * @desc  : add a fd to fd_set
 * @param : ev_loop, the event-loop
 * @param : fd, socket fd
 * @param : event_type, EV_READABLE or EV_WRITEABLE
 */
static void ev_add_event( ev_loop_struct * ev_loop, int fd, int event_type ) {
    /*
     struct epoll_event {
       __uint32_t   events;
       epoll_data_t data;
     };
     typedef union epoll_data {
       void     * ptr;
       int      fd;
       uint32_t uint32;
       uint64_t uint64;
     } epoll_data_t;
     */
    ev_fd_entry_struct * fd_entry;
    struct epoll_event event;
    fd_entry = ev_loop->fd_entry;
    event.data.fd = fd;
    event.events  = EPOLLIN;
    event.events  |= EPOLLET;
    epoll_ctl( fd_entry->epoll_fd, EPOLL_CTL_ADD, fd, &event );
}

/*
 * @desc  : add a fd to fd_set
 * @param : ev_loop, the event-loop
 * @param : fd, socket fd
 * @param : event_type, EV_READABLE or EV_WRITEABLE
 */
static void ev_del_event( ev_loop_struct * ev_loop, int fd, int event_type ) {
    ev_fd_entry_struct * fd_entry;
    struct epoll_event event;
    fd_entry = ev_loop->fd_entry;
    epoll_ctl( fd_entry->epoll_fd, EPOLL_CTL_DEL, fd, &event );
}

/*
 * @desc   : begin an event loop
 * @return : return activity fd
 */
static int ev_poll( ev_loop_struct * ev_loop ) {
    /*
     struct epoll_event {
       __uint32_t   events;
       epoll_data_t data;
     };
     typedef union epoll_data {
       void     * ptr;
       int      fd;
       uint32_t uint32;
       uint64_t uint64;
     } epoll_data_t;
     */
    struct epoll_event   * event;
    ev_file_event_struct * file_event;
    ev_fire_event_struct * fire_event;
    ev_fd_entry_struct   * fd_entry;
    int activity_fd_num = 0;
    int activity_fd_ret = 0;
    fd_entry = ev_loop->fd_entry;
    //events   = fd_entry->events;
    activity_fd_num = epoll_wait( fd_entry->epoll_fd, fd_entry->events, ev_loop->event_size, -1 );
    //printf( "epoll.c : activity_fd_num : %d\n", activity_fd_num );
    if ( activity_fd_num > 0 ) {
        // loop the epoll-ready-event
        for ( int i = 0; i < activity_fd_num; i++ ) {
            event = &( fd_entry->events[ i ] );
            file_event = &( ev_loop->file_events[ event->data.fd ] );
            fire_event = &( ev_loop->fire_events[ activity_fd_ret ] );
            fire_event->event_type = file_event->event_type;
            fire_event->fd = event->data.fd;
            activity_fd_ret++;
        }
    }
    return activity_fd_ret;
}

/*
 * @desc   : get the IO/multiple name
 * @return : string
 */
static char * ev_name() {
    return "epoll";
}


<|start_filename|>datastructure/string.h<|end_filename|>
typedef struct sds_struct {
    size_t free;
    size_t length;
    char   buf[];
} sds_struct;
sds_struct * sds_init( char * );
void sds_empty( sds_struct * );
void sds_strcat( char *, char * );
void sds_strcpy( char *, char * );
size_t sds_get_length( sds_struct * );
size_t sds_get_free( sds_struct * );


<|start_filename|>temp/tistr.h<|end_filename|>
typedef struct tistr_struct {
    size_t free;
    size_t length;
    char * buf;
} tistr_struct;
tistr_struct * tistr_init(char *);
void tistr_truncate(tistr_struct *);
void tistr_empty(tistr_struct *);
void tistr_strcat(char *, char *);
void tistr_strcpy(char *, char *);
size_t tistr_get_length(tistr_struct *);
size_t tistr_get_free(tistr_struct *);
char * tistr_expansion(tistr_struct *, size_t)

<|start_filename|>temp/tilink.h<|end_filename|>
#define ITERATOR_HEAD_TO_TAIL 0
#define ITERATOR_TAIL_TO_HEAD 1
// 链表entry
typedef struct tilink_entry_struct {
    tilink_node_struct * head;  // 链表尾node
    tilink_node_struct * tail;  // 链表头node
    unsigned long length;  // 当前链表一共多少个元素(size_t与unsigned long区别)
} tilink_entry_struct;
// 链表节点
typedef struct tilink_node_struct {
    tilink_node_struct * prev;
    tilink_node_struct * next;
    void * value;  // 该node的value保存到此
} tilink_node_struct;
// 遍历用的临时节点结构
typedef struct tilink_iterator_struct {
    tilink_node_struct * next;
    int direction;  // 表示方向 0表示从头到尾，1表示从尾到头
} tilink_iterator_struct;

// 创建一个空的list，不带任何node
tilink_entry_struct * link_init();
// 初始化一个node
tilink_node_struct * node_init();
// 添加一个head node
void add_head(tilink_entry_struct *, tilink_node_struct *);
// 添加一个tail node
void add_tail(tilink_entry_struct *, tilink_node_struct *);
// 添加到指定位置node
void add_node_2_assign();
// 根据index获取node
tilink_node_struct * get_node_by_index(tilink_entry_struct *, unsigned long);
// 根据value获取node
tilink_node_struct * get_node_by_value(tilink_entry_struct *, void *);
// 遍历link的公用方法，双向
tilink_node_struct * link_next(tilink_iterator_struct *);
// rewind link-list到head处
void reset_link_2_head(tilink_entry_struct *, tilink_iterator_struct *);
// 返回头部node
tilink_node_struct * get_link_head(tilink_entry_struct *);
// 返回尾巴node
tilink_node_struct * get_link_tail(tilink_entry_struct *);
// 获取link长度
unsigned long get_link_length(tilink_entry_struct *);

<|start_filename|>event/ev_factory.c<|end_filename|>
#include "../config.h"
#include "ev_factory.h"
#ifdef IS_EPOLL
#include "epoll.c"
#else
#include "select.c"
#endif

/*
 * @desc  : init the ev_loop_struct
 * @param : size, the size of normal event & fire event
 */
ev_loop_struct * init_ev( int size ) {
    ev_loop_struct * ev = ( ev_loop_struct * )malloc( sizeof( ev_loop_struct ) );
    ev->event_size = size;
    if ( NULL == ev ) {
        return NULL;
    }
    ev->file_events = ( ev_file_event_struct * )malloc( sizeof( ev_file_event_struct ) * size );
    if ( NULL == ev ) {
        return NULL;
    }
    ev->fire_events = ( ev_fire_event_struct * )malloc( sizeof( ev_fire_event_struct ) * size );
    if ( NULL == ev ) {
        return NULL;
    }
    ev_create_fd_entry( ev );
    // init every fd-event's mask
    for ( int i = 0; i < size; i++ ) {
        (ev->file_events[ i ]).event_type = EV_NONE;
    }
    ev->tv_out = NULL;
    ev->max_fd = -1;  // notice:0 1 2
    return ev;
}

/*
 * @desc  : create an file event
 * @param : ev_loop
 * @param : fd
 * @param : processor, event processor
 * @param : event_type
 */
void ev_create_file_event( ev_loop_struct * ev_loop, int fd, file_event_processor * processor, int event_type ) {
    // the memory for file event struct of fd is created when in init_ev function.
    // so, we directly take it out
    ev_file_event_struct * file_event = &( ev_loop->file_events[ fd ] );
    file_event->read_processor  = processor;
    file_event->write_processor = processor;
    file_event->event_type      = event_type;
    ev_loop->max_fd = fd;
    //printf( "ev_factory.c | ev_create_file_event | ev_loop->max_fd:%d\n", ev_loop->max_fd );
    // add fd to select\epoll\poll
    ev_add_event( ev_loop, fd, event_type );
}

/*
 * @desc   : begin an event loop
 * @return : return activity fd
 */
int ev_process( ev_loop_struct * ev_loop ) {
    int activity_fd_num;
    // the server will lose in LOOP!
    for( ; ; ) {
        // block at SELECT/EPOLL/POLL system call
        activity_fd_num = ev_poll( ev_loop );
        if ( activity_fd_num > 0 ) {
            for ( int i = 0; i < activity_fd_num; i++ ) {
                // take out the event for the fd from ev_loop->events
                ev_fire_event_struct * fire_event = &( ev_loop->fire_events[ i ] );
                //printf( "ev_factory.c | fire_event->fd:%d\n", fire_event->fd );
                ev_file_event_struct * file_event = &( ev_loop->file_events[ fire_event->fd ] );
                if ( EV_READABLE == fire_event->event_type ) {
                    file_event->read_processor( ev_loop, fire_event->fd );
                }
                else if ( EV_WRITEABLE == fire_event->event_type ) {

                }
            }
        }
    }
    return 0;
}

/*
 * @desc  : event main function
 */
void ev_main( ev_loop_struct * ev_loop ) {
    ev_process( ev_loop );
}

/*
 * @desc   : get the IO/multiple name
 * @return : string
 */
static char * ev_get_name() {
    return ev_name();
}

<|start_filename|>event/select.c<|end_filename|>
#include <sys/select.h>

/*
 * @desc : fd for select API
 */
typedef struct ev_fd_entry_struct {
    fd_set read_fds;
    fd_set _read_fds;
    fd_set write_fds;
    fd_set _write_fds;
} ev_fd_entry_struct;

/*
 * @desc : create fd entry for ev_factory's ev_loop struct
 */
static void ev_create_fd_entry( ev_loop_struct * ev_loop ) {
    ev_fd_entry_struct * fd_entry = ( ev_fd_entry_struct * )malloc( sizeof( ev_fd_entry_struct ) );
    // clear the fd_set to ZERO!
    FD_ZERO( &( fd_entry->read_fds ) );
    FD_ZERO( &( fd_entry->_read_fds ) );
    FD_ZERO( &( fd_entry->write_fds ) );
    FD_ZERO( &( fd_entry->_write_fds ) );
    ev_loop->fd_entry = fd_entry;
}

/*
 * @desc : add a fd to fd_set
 */
static void ev_add_event( ev_loop_struct * ev_loop, int fd, int event_type ) {
    ev_fd_entry_struct * fd_entry = ev_loop->fd_entry;
    // add to different fd_set via different event_type
    if ( EV_READABLE == event_type ) {
        // if you can'not remember whether -> first or & first
        // so song( -_- ) a little, just use () to help you
        FD_SET( fd, &( fd_entry->read_fds ) );
    }
    if ( EV_WRITEABLE == event_type ) {
        FD_SET( fd, &( fd_entry->write_fds ) );
    }
}

/*
 * @desc : delete a fd to fd_set
 */
static void ev_del_event( ev_loop_struct * ev_loop, int fd, int event_type ) {
    ev_fd_entry_struct * fd_entry = ev_loop->fd_entry;
    if ( EV_READABLE == event_type ) {
        FD_CLR( fd, &( fd_entry->read_fds ) );
    }
    if ( EV_WRITEABLE == event_type ) {
        FD_CLR( fd, &( fd_entry->write_fds ) );
    }
}

/*
 * @desc   : begin an event loop
 * @return : return activity fd
 */
static int ev_poll( ev_loop_struct * ev_loop ) {
    ev_fd_entry_struct * fd_entry = ev_loop->fd_entry;
    int activity_fd_num;
    int activity_fd_ret = 0;
    // 1. DO NOT use fd_entry->_read_fds = fd_entry->read_fds
    // 2. You should know the difference between memset & strcpy
    memcpy( &fd_entry->_read_fds,  &fd_entry->read_fds,  sizeof( fd_set ) );
    memcpy( &fd_entry->_write_fds, &fd_entry->write_fds, sizeof( fd_set ) );
    activity_fd_num = select( ev_loop->max_fd + 1, &fd_entry->_read_fds, NULL, NULL, NULL );
    // promise me, remember put the read-ready or write-ready fd to ev_loop->fire_events array...
    if ( activity_fd_num > 0 ) {
        for ( int i = 0; i <= ev_loop->max_fd; i++ ) {
            ev_file_event_struct * file_event = &( ev_loop->file_events[ i ] );
            if ( EV_NONE == file_event->event_type ) continue;
            ev_fire_event_struct * fire_event = &( ev_loop->fire_events[ activity_fd_ret ] );
            if ( FD_ISSET( i, &fd_entry->_read_fds ) || FD_ISSET( i, &fd_entry->_write_fds ) ) {
                fire_event->fd         = i;
                fire_event->event_type = file_event->event_type;
                activity_fd_ret++;
            }
            //if ( FD_ISSET( i, &fd_entry->_write_fds ) ) {
            //}
        }
    }
    return activity_fd_ret;
}

/*
 * @desc   : get the IO/multiple name
 * @return : string
 */
static char * ev_name() {
    return "select";
}
