Commit for Maxim <3
[build.git] / uniqstr.c
blobd4937616a12bbc6a18adbd81ec01d3308ec6fbf3
1 /* uniqstr.c -- implementation of unique strings used for shortage
2 memory footprint by lot of strings.
4 Copyright (C) 2022 Sergey Sushilin <sergeysushilin@protonmail.com>
6 This file is part of Build.
8 Build is free software: you can redistribute it and/or
9 modify it under the terms of either the GNU General Public License
10 as published by the Free Software Foundation;
11 either version 2 of the License, or version 3 of the License,
12 or both in parallel, as here.
14 Build is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received copies of the GNU General Public License
20 version 2 and 3 along with this program.
21 If not, see http://www.gnu.org/licenses/. */
23 #include <errno.h>
24 #include <stddef.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include "diagnostic.h"
30 #include "hash.h"
31 #include "system.h"
32 #include "uniqstr.h"
33 #include "thread.h"
35 /* Use global variable to simplify API. */
36 static Hash uniqstrs_table;
37 static struct mutex uniqstrs_table_mutex;
39 uniqstr
40 uniqstr_new_from_buffer (char const *str, size_t size)
42 uniqstr res;
43 char *r;
44 uint32_t size32;
46 if (UNLIKELY (size > UINT32_MAX))
48 warning (_("string is too long"));
49 abort ();
52 size32 = (uint32_t) size;
53 mutex_acquire (&uniqstrs_table_mutex);
54 res = HashFind (&uniqstrs_table, str, size32);
55 mutex_release (&uniqstrs_table_mutex);
57 if (res == NULL)
59 /* First insertion in the hash. */
60 r = malloc (sizeof (uint32_t) + size32 + 1);
62 if (UNLIKELY (r == NULL))
63 goto lfail;
65 *(uint32_t *) r = size32;
66 r += sizeof (uint32_t);
67 memcpy (r, str, size32);
68 r[size32] = '\0';
69 mutex_acquire (&uniqstrs_table_mutex);
71 if (UNLIKELY (HashInsert (&uniqstrs_table, r, size32, r) == NULL))
72 goto lfail;
74 mutex_release (&uniqstrs_table_mutex);
75 res = r;
78 return res;
80 lfail:
81 warning (_("memory exhausted"));
82 abort ();
85 uniqstr
86 uniqstr_new (const char *str)
88 return uniqstr_new_from_buffer (str, strlen (str));
91 uint32_t
92 uniqstr_len (uniqstr str)
94 return *(const uint32_t *) (str - sizeof (uint32_t));
97 bool
98 uniqstr_cmp (uniqstr str1, uniqstr str2)
100 return str1 == str2;
103 void *
104 uniqstr_chr (uniqstr str, char c)
106 return memchr (str, c, uniqstr_len (str));
109 void
110 uniqstrs_table_create (void)
112 if (UNLIKELY (!mutex_create (&uniqstrs_table_mutex)))
113 abort ();
115 /* Can not provide uniqstr_hash() since HashFind can be called
116 with non-uniqstr pointer. */
117 HashInit (&uniqstrs_table);
120 static void
121 uniqstr_destroy (void *p)
123 free ((char *) p - sizeof (uint32_t));
126 void
127 uniqstrs_table_destroy (void)
129 HashClearWithDestructor (&uniqstrs_table, uniqstr_destroy);
130 mutex_destroy (&uniqstrs_table_mutex);