summaryrefslogtreecommitdiff
path: root/src/upb_string.h
blob: 9740a0b13da302eafaa65d48d0e946ef4af17329 (plain)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * upb - a minimalist implementation of protocol buffers.
 *
 * Copyright (c) 2009 Joshua Haberman.  See LICENSE for details.

 * Defines a delimited (as opposed to null-terminated) string type and some
 * library functions for manipulating them.
 *
 * There are two primary reasons upb uses delimited strings.  One is that they
 * can be more efficient for some operations because they do not have to scan
 * the string to find its length.  For example, streql can start by just
 * comparing the lengths (very efficient) and scan the strings themselves only
 * if the lengths are equal.
 *
 * More importantly, using delimited strings makes it possible for strings to
 * reference substrings of other strings.  For example, if I am parsing a
 * protobuf I can create a string that references the original protobuf's
 * string data.  With NULL-termination I would be forced to write a NULL
 * into the middle of the protobuf's data, which is less than ideal and in
 * some cases not practical or possible.
 */

#ifndef UPB_STRING_H_
#define UPB_STRING_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

/* inline if possible, emit standalone code if required. */
#ifndef INLINE
#define INLINE static inline
#endif

#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y))
#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y))

struct upb_string {
  /* We expect the data to be 8-bit clean (uint8_t), but char* is such an
   * ingrained convention that we follow it. */
  char *ptr;
  uint32_t byte_len;
  uint32_t byte_size;  /* How many bytes of ptr we own. */
};

INLINE void upb_strinit(struct upb_string *str)
{
  str->ptr = NULL;
  str->byte_len = 0;
  str->byte_size = 0;
}

INLINE void upb_struninit(struct upb_string *str)
{
  if(str->byte_size) free(str->ptr);
}

INLINE struct upb_string *upb_strnew(void)
{
  struct upb_string *str = (struct upb_string*)malloc(sizeof(*str));
  upb_strinit(str);
  return str;
}

INLINE void upb_strfree(struct upb_string *str)
{
  upb_struninit(str);
  free(str);
}

INLINE void upb_stralloc(struct upb_string *str, uint32_t size)
{
  if(str->byte_size < size) {
    /* Need to resize. */
    str->byte_size = size;
    void *oldptr = str->byte_size == 0 ? NULL : str->ptr;
    str->ptr = (char*)realloc(oldptr, str->byte_size);
  }
}

INLINE void upb_strdrop(struct upb_string *str)
{
  upb_struninit(str);
}

INLINE bool upb_streql(struct upb_string *s1, struct upb_string *s2) {
  return s1->byte_len == s2->byte_len &&
         memcmp(s1->ptr, s2->ptr, s1->byte_len) == 0;
}

INLINE int upb_strcmp(struct upb_string *s1, struct upb_string *s2) {
  size_t common_length = UPB_MIN(s1->byte_len, s2->byte_len);
  int common_diff = memcmp(s1->ptr, s2->ptr, common_length);
  return common_diff == 0 ? (int)s1->byte_len - (int)s2->byte_len : common_diff;
}

INLINE void upb_strcpy(struct upb_string *dest, struct upb_string *src) {
  dest->byte_len = src->byte_len;
  upb_stralloc(dest, dest->byte_len);
  memcpy(dest->ptr, src->ptr, src->byte_len);
}

INLINE struct upb_string *upb_strdup(struct upb_string *s) {
  struct upb_string *copy = upb_strnew();
  upb_strcpy(copy, s);
  return copy;
}

INLINE struct upb_string *upb_strdupc(char *s) {
  struct upb_string *copy = upb_strnew();
  copy->byte_len = strlen(s);
  upb_stralloc(copy, copy->byte_len);
  memcpy(copy->ptr, s, copy->byte_len);
  return copy;
}

/* Reads an entire file into a newly-allocated string. */
bool upb_strreadfile(const char *filename, struct upb_string *data);

/* Allows defining upb_strings as literals, ie:
 *   struct upb_string str = UPB_STRLIT("Hello, World!\n");
 * Doesn't work with C++ due to lack of struct initializer syntax.
 */
#define UPB_STRLIT(strlit) {.ptr=strlit, .byte_len=sizeof(strlit)-1}

/* Allows using upb_strings in printf, ie:
 *   struct upb_string str = UPB_STRLIT("Hello, World!\n");
 *   printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */
#define UPB_STRARG(str) (str)->byte_len, (str)->ptr
#define UPB_STRFMT "%.*s"

#ifdef __cplusplus
}  /* extern "C" */
#endif

#endif  /* UPB_H_ */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback