homework-jianmu/tools/shell/src/shellTire.c

411 lines
8.6 KiB
C

/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the GNU Affero General Public License, version 3
* or later ("AGPL"), as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define __USE_XOPEN
#include "os.h"
#include "shellTire.h"
// ----------- interface -------------
// create prefix search tree
STire* createTire(char type) {
STire* tire = taosMemoryMalloc(sizeof(STire));
memset(tire, 0, sizeof(STire));
tire->ref = 1; // init is 1
tire->type = type;
tire->root.d = (STireNode**)taosMemoryCalloc(CHAR_CNT, sizeof(STireNode*));
return tire;
}
// free tire node
void freeTireNode(STireNode* node) {
if (node == NULL) return;
// nest free sub node on array d
if (node->d) {
for (int i = 0; i < CHAR_CNT; i++) {
freeTireNode(node->d[i]);
}
taosMemoryFree(node->d);
}
// free self
taosMemoryFree(node);
}
// destroy prefix search tree
void freeTire(STire* tire) {
// free nodes
for (int i = 0; i < CHAR_CNT; i++) {
freeTireNode(tire->root.d[i]);
}
taosMemoryFree(tire->root.d);
// free from list
StrName* item = tire->head;
while (item) {
StrName* next = item->next;
// free string
taosMemoryFree(item->name);
// free node
taosMemoryFree(item);
// move next
item = next;
}
tire->head = tire->tail = NULL;
// free tire
taosMemoryFree(tire);
}
// insert a new word to list
bool insertToList(STire* tire, char* word) {
StrName* p = (StrName*)taosMemoryMalloc(sizeof(StrName));
p->name = taosStrdup(word);
p->next = NULL;
if (tire->head == NULL) {
tire->head = p;
tire->tail = p;
} else {
tire->tail->next = p;
tire->tail = p;
}
return true;
}
// insert a new word to tree
bool insertToTree(STire* tire, char* word, int len) {
int m = 0;
STireNode** nodes = tire->root.d;
for (int i = 0; i < len; i++) {
m = word[i] - FIRST_ASCII;
if (m < 0 || m >= CHAR_CNT) {
return false;
}
if (nodes[m] == NULL) {
// no pointer
STireNode* p = (STireNode*)taosMemoryMalloc(sizeof(STireNode));
memset(p, 0, sizeof(STireNode));
nodes[m] = p;
if (i == len - 1) {
// is end
p->end = true;
break;
}
}
if (nodes[m]->d == NULL) {
// malloc d
nodes[m]->d = (STireNode**)taosMemoryCalloc(CHAR_CNT, sizeof(STireNode*));
}
// move to next node
nodes = nodes[m]->d;
}
// add count
tire->count += 1;
return true;
}
// insert a new word
bool insertWord(STire* tire, char* word) {
int len = strlen(word);
if (len >= MAX_WORD_LEN) {
return false;
}
switch (tire->type) {
case TIRE_TREE:
return insertToTree(tire, word, len);
case TIRE_LIST:
return insertToList(tire, word);
default:
break;
}
return false;
}
// delete one word from list
bool deleteFromList(STire* tire, char* word) {
StrName* item = tire->head;
while (item) {
if (strcmp(item->name, word) == 0) {
// found, reset empty to delete
item->name[0] = 0;
}
// move next
item = item->next;
}
return true;
}
// delete one word from tree
bool deleteFromTree(STire* tire, char* word, int len) {
int m = 0;
bool del = false;
STireNode** nodes = tire->root.d;
for (int i = 0; i < len; i++) {
m = word[i] - FIRST_ASCII;
if (m < 0 || m >= CHAR_CNT) {
return false;
}
if (nodes[m] == NULL) {
// no found
return false;
} else {
// not null
if (i == len - 1) {
// this is last, only set end false , not free node
nodes[m]->end = false;
del = true;
break;
}
}
if (nodes[m]->d == NULL) break;
// move to next node
nodes = nodes[m]->d;
}
// reduce count
if (del) {
tire->count -= 1;
}
return del;
}
// insert a new word
bool deleteWord(STire* tire, char* word) {
int len = strlen(word);
if (len >= MAX_WORD_LEN) {
return false;
}
switch (tire->type) {
case TIRE_TREE:
return deleteFromTree(tire, word, len);
case TIRE_LIST:
return deleteFromList(tire, word);
default:
break;
}
return false;
}
void addWordToMatch(SMatch* match, char* word) {
// malloc new
SMatchNode* node = (SMatchNode*)taosMemoryMalloc(sizeof(SMatchNode));
memset(node, 0, sizeof(SMatchNode));
node->word = taosStrdup(word);
// append to match
if (match->head == NULL) {
match->head = match->tail = node;
} else {
match->tail->next = node;
match->tail = node;
}
match->count += 1;
}
// enum all words from node
void enumAllWords(STireNode** nodes, char* prefix, SMatch* match) {
STireNode* c;
char word[MAX_WORD_LEN];
int len = strlen(prefix);
for (int i = 0; i < CHAR_CNT; i++) {
c = nodes[i];
if (c == NULL) {
// chain end node
continue;
} else {
// combine word string
memset(word, 0, tListLen(word));
strncpy(word, prefix, len);
word[len] = FIRST_ASCII + i; // append current char
// chain middle node
if (c->end) {
// have end flag
addWordToMatch(match, word);
}
// nested call next layer
if (c->d) enumAllWords(c->d, word, match);
}
}
}
// match prefix from list
void matchPrefixFromList(STire* tire, char* prefix, SMatch* match) {
StrName* item = tire->head;
int len = strlen(prefix);
while (item) {
if (strncmp(item->name, prefix, len) == 0) {
// prefix matched
addWordToMatch(match, item->name);
}
// move next
item = item->next;
}
}
// match prefix words, if match is not NULL , put all item to match and return match
void matchPrefixFromTree(STire* tire, char* prefix, SMatch* match) {
int m = 0;
STireNode* c = 0;
int len = strlen(prefix);
if (len >= MAX_WORD_LEN) {
return;
}
STireNode** nodes = tire->root.d;
for (int i = 0; i < len; i++) {
m = prefix[i] - FIRST_ASCII;
if (m < 0 || m > CHAR_CNT) {
return;
}
// match
c = nodes[m];
if (c == NULL) {
// arrive end
break;
}
// previous items already matched
if (i == len - 1) {
// prefix is match to end char
if (c->d) enumAllWords(c->d, prefix, match);
} else {
// move to next node continue match
if (c->d == NULL) break;
nodes = c->d;
}
}
}
void matchPrefix(STire* tire, char* prefix, SMatch* match) {
if (match == NULL) {
return;
}
switch (tire->type) {
case TIRE_TREE:
matchPrefixFromTree(tire, prefix, match);
break;
case TIRE_LIST:
matchPrefixFromList(tire, prefix, match);
break;
default:
break;
}
}
// get all items from tires tree
void enumFromList(STire* tire, SMatch* match) {
StrName* item = tire->head;
while (item) {
if (item->name[0] != 0) {
// not delete
addWordToMatch(match, item->name);
}
// move next
item = item->next;
}
}
// get all items from tires tree
void enumFromTree(STire* tire, SMatch* match) {
char pre[2] = {0, 0};
STireNode* c;
// enum first layer
for (int i = 0; i < CHAR_CNT; i++) {
pre[0] = FIRST_ASCII + i;
// each node
c = tire->root.d[i];
if (c == NULL) {
// this branch no data
continue;
}
// this branch have data
if (c->end) {
addWordToMatch(match, pre);
} else {
matchPrefix(tire, pre, match);
}
}
}
// get all items from tires tree
SMatch* enumAll(STire* tire) {
SMatch* match = (SMatch*)taosMemoryMalloc(sizeof(SMatch));
memset(match, 0, sizeof(SMatch));
switch (tire->type) {
case TIRE_TREE:
enumFromTree(tire, match);
break;
case TIRE_LIST:
enumFromList(tire, match);
break;
default:
break;
}
// return if need
if (match->count == 0) {
freeMatch(match);
match = NULL;
}
return match;
}
// free match result
void freeMatchNode(SMatchNode* node) {
// first free next
if (node->next) freeMatchNode(node->next);
// second free self
if (node->word) taosMemoryFree(node->word);
taosMemoryFree(node);
}
// free match result
void freeMatch(SMatch* match) {
// first free next
if (match->head) {
freeMatchNode(match->head);
}
// second free self
taosMemoryFree(match);
}