summary refs log tree commit diff stats
path: root/lib/system/setops.nim
blob: 755eafdb81b78dcc7aa3b726e419fcd1c37d6fce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
func incl*[T](x: var set[T], y: T) {.magic: "Incl".} =
  ## Includes element `y` in the set `x`.
  ##
  ## This is the same as `x = x + {y}`, but it might be more efficient.
  runnableExamples:
    var a = {1, 3, 5}
    a.incl(2)
    assert a == {1, 2, 3, 5}
    a.incl(4)
    assert a == {1, 2, 3, 4, 5}

template incl*[T](x: var set[T], y: set[T]) =
  ## Includes the set `y` in the set `x`.
  runnableExamples:
    var a = {1, 3, 5, 7}
    var b = {4, 5, 6}
    a.incl(b)
    assert a == {1, 3, 4, 5, 6, 7}
  x = x + y

func excl*[T](x: var set[T], y: T) {.magic: "Excl".} =
  ## Excludes element `y` from the set `x`.
  ##
  ## This is the same as `x = x - {y}`, but it might be more efficient.
  runnableExamples:
    var b = {2, 3, 5, 6, 12, 545}
    b.excl(5)
    assert b == {2, 3, 6, 12, 545}

template excl*[T](x: var set[T], y: set[T]) =
  ## Excludes the set `y` from the set `x`.
  runnableExamples:
    var a = {1, 3, 5, 7}
    var b = {3, 4, 5}
    a.excl(b) 
    assert a == {1, 7}
  x = x - y

func card*[T](x: set[T]): int {.magic: "Card".} =
  ## Returns the cardinality of the set `x`, i.e. the number of elements
  ## in the set.
  runnableExamples:
    var a = {1, 3, 5, 7}
    assert card(a) == 4
    var b = {1, 3, 5, 7, 5}
    assert card(b) == 4 # repeated 5 doesn't count

func len*[T](x: set[T]): int {.magic: "Card".}
  ## An alias for `card(x)`.


func `*`*[T](x, y: set[T]): set[T] {.magic: "MulSet".} =
  ## This operator computes the intersection of two sets.
  runnableExamples:
    assert {1, 2, 3} * {2, 3, 4} == {2, 3}

func `+`*[T](x, y: set[T]): set[T] {.magic: "PlusSet".} =
  ## This operator computes the union of two sets.
  runnableExamples:
    assert {1, 2, 3} + {2, 3, 4} == {1, 2, 3, 4}

func `-`*[T](x, y: set[T]): set[T] {.magic: "MinusSet".} =
  ## This operator computes the difference of two sets.
  runnableExamples:
    assert {1, 2, 3} - {2, 3, 4} == {1}

func contains*[T](x: set[T], y: T): bool {.magic: "InSet".} =
  ## One should overload this proc if one wants to overload the `in` operator.
  ##
  ## The parameters are in reverse order! `a in b` is a template for
  ## `contains(b, a)`.
  ## This is because the unification algorithm that Nim uses for overload
  ## resolution works from left to right.
  ## But for the `in` operator that would be the wrong direction for this
  ## piece of code:
  runnableExamples:
    var s: set[range['a'..'z']] = {'a'..'c'}
    assert s.contains('c')
    assert 'b' in s
    assert 'd' notin s
    assert set['a'..'z'] is set[range['a'..'z']]
  ## If `in` had been declared as `[T](elem: T, s: set[T])` then `T` would
  ## have been bound to `char`. But `s` is not compatible to type
  ## `set[char]`! The solution is to bind `T` to `range['a'..'z']`. This
  ## is achieved by reversing the parameters for `contains`; `in` then
  ## passes its arguments in reverse order.
n class="p">{ winsch(inp_win, *ch); wmove(inp_win, inp_y, inp_x+1); for (i = *size; i > inp_x -1; i--) input[i] = input[i-1]; input[inp_x -1] = *ch; (*size)++; // otherwise just append } else { waddch(inp_win, *ch); input[(*size)++] = *ch; } reset_search_attempts(); reset_login_search(); reset_command_completer(); } } echo(); } void inp_get_password(char *passwd) { wclear(inp_win); noecho(); mvwgetnstr(inp_win, 0, 1, passwd, 20); wmove(inp_win, 0, 1); echo(); status_bar_clear(); } void inp_put_back(void) { wrefresh(inp_win); } /* * Deal with command editing, return 1 if ch was an edit * key press: up, down, left, right or backspace * return 0 if it wasnt */ static int _handle_edit(const int ch, char *input, int *size) { int i; char *prev = NULL; char *next = NULL; char *found = NULL; char *auto_msg = NULL; int inp_y = 0; int inp_x = 0; char inp_cpy[*size]; getyx(inp_win, inp_y, inp_x); switch(ch) { case 127: case KEY_BACKSPACE: reset_search_attempts(); if (*size > 0) { // if at end, delete last char if (inp_x > *size) { wmove(inp_win, inp_y, inp_x-1); wdelch(inp_win); (*size)--; // if in middle, delete and shift chars left } else if (inp_x > 1 && inp_x <= *size) { for (i = inp_x-1; i < *size; i++) input[i-1] = input[i]; (*size)--; inp_clear(); for (i = 0; i < *size; i++) waddch(inp_win, input[i]); wmove(inp_win, 0, inp_x -1); } } return 1; case KEY_DC: // DEL if (inp_x <= *size) { wdelch(inp_win); // if not last char, shift chars left if (inp_x < *size) for (i = inp_x-1; i < *size; i++) input[i] = input[i+1]; (*size)--; } return 1; case KEY_LEFT: if (inp_x > 1) wmove(inp_win, inp_y, inp_x-1); return 1; case KEY_RIGHT: if (inp_x <= *size ) wmove(inp_win, inp_y, inp_x+1); return 1; case KEY_UP: prev = history_previous(input, size); if (prev) _replace_input(input, prev, size); return 1; case KEY_DOWN: next = history_next(input, size); if (next) _replace_input(input, next, size); return 1; case KEY_HOME: wmove(inp_win, inp_y, 1); return 1; case KEY_END: wmove(inp_win, inp_y, (*size) + 1); return 1; case 9: // tab // autocomplete commands if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, *size, ' '))) { for(i = 0; i < *size; i++) { inp_cpy[i] = input[i]; } inp_cpy[i] = '\0'; found = cmd_complete(inp_cpy); if (found != NULL) { auto_msg = (char *) malloc((strlen(found) + 1) * sizeof(char)); strcpy(auto_msg, found); _replace_input(input, auto_msg, size); free(auto_msg); free(found); } // autcomplete /msg recipient } else if ((strncmp(input, "/msg ", 5) == 0) && (*size > 5)) { for(i = 5; i < *size; i++) { inp_cpy[i-5] = input[i]; } inp_cpy[(*size) - 5] = '\0'; found = find_contact(inp_cpy); if (found != NULL) { auto_msg = (char *) malloc((5 + (strlen(found) + 1)) * sizeof(char)); strcpy(auto_msg, "/msg "); strcat(auto_msg, found); _replace_input(input, auto_msg, size); free(auto_msg); free(found); } // autocomplete /connect username } else if ((strncmp(input, "/connect ", 9) == 0) && (*size > 9)) { for(i = 9; i < *size; i++) { inp_cpy[i-9] = input[i]; } inp_cpy[(*size) - 9] = '\0'; found = find_login(inp_cpy); if (found != NULL) { auto_msg = (char *) malloc((9 + (strlen(found) + 1)) * sizeof(char)); strcpy(auto_msg, "/connect "); strcat(auto_msg, found); _replace_input(input, auto_msg, size); free(auto_msg); free(found); } } return 1; default: return 0; } } static int _printable(const int ch) { return (ch != ERR && ch != '\n' && ch != KEY_PPAGE && ch != KEY_NPAGE && ch != KEY_F(1) && ch != KEY_F(2) && ch != KEY_F(3) && ch != KEY_F(4) && ch != KEY_F(5) && ch != KEY_F(6) && ch != KEY_F(7) && ch != KEY_F(8) && ch != KEY_F(9) && ch != KEY_F(10) && ch!= KEY_F(11) && ch != KEY_F(12) && ch != KEY_IC && ch != KEY_EIC && ch != KEY_RESIZE); } static void _replace_input(char *input, const char * const new_input, int *size) { int i; strcpy(input, new_input); *size = strlen(input); inp_clear(); for (i = 0; i < *size; i++) waddch(inp_win, input[i]); }