OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TableFunctionsFactory_declbracket.py
Go to the documentation of this file.
1 import TableFunctionsFactory_util as util
2 
3 
4 class Declaration:
5  """Holds a `TYPE | ANNOTATIONS`-like structure.
6  """
7  def __init__(self, type, annotations=[]):
8  self.type = type
9  self.annotations = annotations
10 
11  @property
12  def name(self):
13  return self.type.name
14 
15  @property
16  def args(self):
17  return self.type.args
18 
19  def format_sizer(self):
20  return self.type.format_sizer()
21 
22  def __repr__(self):
23  return 'Declaration(%r, ann=%r)' % (self.type, self.annotations)
24 
25  def __str__(self):
26  if not self.annotations:
27  return str(self.type)
28  return '%s | %s' % (self.type, ' | '.join(map(str, self.annotations)))
29 
30  def tostring(self):
31  return self.type.tostring()
32 
33  def apply_column(self):
34  return self.__class__(self.type.apply_column(), self.annotations)
35 
36  def apply_namespace(self, ns='ExtArgumentType'):
37  return self.__class__(self.type.apply_namespace(ns), self.annotations)
38 
39  def get_cpp_type(self):
40  return self.type.get_cpp_type()
41 
42  def format_cpp_type(self, idx, use_generic_arg_name=False, is_input=True):
43  real_arg_name = dict(self.annotations).get('name', None)
44  return self.type.format_cpp_type(idx,
45  use_generic_arg_name=use_generic_arg_name,
46  real_arg_name=real_arg_name,
47  is_input=is_input)
48 
49  def __getattr__(self, name):
50  if name.startswith('is_'):
51  return getattr(self.type, name)
52  raise AttributeError(name)
53 
54 
55 class Bracket:
56  """Holds a `NAME<ARGS>`-like structure.
57  """
58 
59  def __init__(self, name, args=None):
60  assert isinstance(name, str)
61  assert isinstance(args, tuple) or args is None, args
62  self.name = name
63  self.args = args
64 
65  def __repr__(self):
66  return 'Bracket(%r, args=%r)' % (self.name, self.args)
67 
68  def __str__(self):
69  if not self.args:
70  return self.name
71  return '%s<%s>' % (self.name, ', '.join(map(str, self.args)))
72 
73  def tostring(self):
74  if not self.args:
75  return self.name
76  return '%s<%s>' % (self.name, ', '.join(map(util.tostring, self.args)))
77 
78  def normalize(self, kind='input'):
79  """Normalize bracket for given kind
80  """
81  assert kind in ['input', 'output'], kind
82  if self.is_column_any() and self.args:
83  return Bracket(self.name + ''.join(map(str, self.args)))
84  if kind == 'input':
85  if self.name == 'Cursor':
86  args = [(a if a.is_column_any() else Bracket('Column', args=(a,))).normalize(kind=kind) for a in self.args]
87  return Bracket(self.name, tuple(args))
88  if kind == 'output':
89  if not self.is_column_any():
90  return Bracket('Column', args=(self,)).normalize(kind=kind)
91  return self
92 
93  def apply_cursor(self):
94  """Apply cursor to a non-cursor column argument type.
95  TODO: this method is currently unused but we should apply
96  cursor to all input column arguments in order to distingush
97  signatures like:
98  foo(Cursor(Column<int32>, Column<float>)) -> Column<int32>
99  foo(Cursor(Column<int32>), Cursor(Column<float>)) -> Column<int32>
100  that at the moment are treated as the same :(
101  """
102  if self.is_column():
103  return Bracket('Cursor', args=(self,))
104  return self
105 
106  def apply_column(self):
107  if not self.is_column() and not self.is_column_list():
108  return Bracket('Column' + self.name)
109  return self
110 
111  def apply_namespace(self, ns='ExtArgumentType'):
112  if self.name == 'Cursor':
113  return Bracket(ns + '::' + self.name, args=tuple(a.apply_namespace(ns=ns) for a in self.args))
114  if not self.name.startswith(ns + '::'):
115  return Bracket(ns + '::' + self.name)
116  return self
117 
118  def is_cursor(self):
119  return self.name.rsplit("::", 1)[-1] == 'Cursor'
120 
121  def is_array(self):
122  return self.name.rsplit("::", 1)[-1].startswith('Array')
123 
124  def is_column_any(self):
125  return self.name.rsplit("::", 1)[-1].startswith('Column')
126 
127  def is_column_list(self):
128  return self.name.rsplit("::", 1)[-1].startswith('ColumnList')
129 
130  def is_column(self):
131  return self.name.rsplit("::", 1)[-1].startswith('Column') and not self.is_column_list()
132 
134  return self.name.rsplit("::", 1)[-1].endswith('TextEncodingDict')
135 
137  return self.name.rsplit("::", 1)[-1] == 'ArrayTextEncodingDict'
138 
140  return self.name.rsplit("::", 1)[-1] == 'ColumnTextEncodingDict'
141 
143  return self.name.rsplit("::", 1)[-1] == 'ColumnArrayTextEncodingDict'
144 
146  return self.name.rsplit("::", 1)[-1] == 'ColumnListTextEncodingDict'
147 
149  return self.name.rsplit("::", 1)[-1] in util.OutputBufferSizeTypes
150 
151  def is_row_multiplier(self):
152  return self.name.rsplit("::", 1)[-1] == 'kUserSpecifiedRowMultiplier'
153 
154  def is_arg_sizer(self):
155  return self.name.rsplit("::", 1)[-1] == 'kPreFlightParameter'
156 
157  def is_user_specified(self):
158  # Return True if given argument cannot specified by user
159  if self.is_output_buffer_sizer():
160  return self.name.rsplit("::", 1)[-1] not in ('kConstant', 'kTableFunctionSpecifiedParameter', 'kPreFlightParameter')
161  return True
162 
163  def format_sizer(self):
164  val = 0 if self.is_arg_sizer() else self.args[0]
165  return 'TableFunctionOutputRowSizer{OutputBufferSizeType::%s, %s}' % (self.name, val)
166 
167  def get_cpp_type(self):
168  name = self.name.rsplit("::", 1)[-1]
169  clsname = None
170  subclsname = None
171  if name.startswith('ColumnList'):
172  name = name.lstrip('ColumnList')
173  clsname = 'ColumnList'
174  elif name.startswith('Column'):
175  name = name.lstrip('Column')
176  clsname = 'Column'
177  if name.startswith('Array'):
178  name = name.lstrip('Array')
179  if clsname is None:
180  clsname = 'Array'
181  else:
182  subclsname = 'Array'
183 
184  if name.startswith('Bool'):
185  ctype = name.lower()
186  elif name.startswith('Int'):
187  ctype = name.lower() + '_t'
188  elif name in ['Double', 'Float']:
189  ctype = name.lower()
190  elif name == 'TextEncodingDict':
191  ctype = name
192  elif name == 'TextEncodingNone':
193  ctype = name
194  elif name == 'Timestamp':
195  ctype = name
196  elif name == 'DayTimeInterval':
197  ctype = name
198  elif name == 'YearMonthTimeInterval':
199  ctype = name
200  elif name in ['GeoPoint', 'GeoLineString', 'GeoPolygon',
201  'GeoMultiPoint', 'GeoMultiLineString', 'GeoMultiPolygon']:
202  ctype = name
203  else:
204  raise NotImplementedError(self)
205  if clsname is None:
206  return ctype
207  if subclsname is None:
208  return '%s<%s>' % (clsname, ctype)
209  return '%s<%s<%s>>' % (clsname, subclsname, ctype)
210 
211  def format_cpp_type(self, idx, use_generic_arg_name=False, real_arg_name=None, is_input=True):
212  # Arguments that types are derived from arithmetic and bool
213  # types, should be passed by value:
214  pass_by_value_typs =(
215  'bool', 'int8_t', 'int16_t', 'int32_t', 'int64_t', 'float',
216  'double', 'Timestamp', 'DayTimeInterval', 'YearMonthTimeInterval', 'TextEncodingDict')
217  # Arguments that types are of struct type, should be passed by
218  # reference:
219  pass_by_reference_typs =('Column', 'ColumnList', 'TextEncodingNone', 'Array')
220 
221  if use_generic_arg_name:
222  arg_name = 'input' + str(idx) if is_input else 'output' + str(idx)
223  elif real_arg_name is not None:
224  arg_name = real_arg_name
225  else:
226  # in some cases, the real arg name is not specified
227  arg_name = 'input' + str(idx) if is_input else 'output' + str(idx)
228  const = 'const ' if is_input else ''
229  cpp_type = self.get_cpp_type()
230  if any(cpp_type.startswith(t) for t in pass_by_reference_typs):
231  return '%s%s& %s' % (const, cpp_type, arg_name), arg_name
232  elif any(cpp_type.startswith(t) for t in pass_by_value_typs):
233  return '%s %s' % (cpp_type, arg_name), arg_name
234  else:
235  msg =('Argument passing policy for argument `%s` of C++ type `%s` is unspecified.'
236  ' Update pass_by_value_typs or pass_by_reference_typs in'
237  ' Declaration.format_cpp_type to indicate the desired argument'
238  ' passing policy.') %(arg_name, cpp_type)
239  raise NotImplementedError(msg)
240 
241  @classmethod
242  def parse(cls, typ):
243  """typ is a string in format NAME<ARGS> or NAME
244  Returns Bracket instance.
245  """
246  i = typ.find('<')
247  if i == -1:
248  name = typ.strip()
249  args = None
250  else:
251  assert typ.endswith('>'), typ
252  name = typ[:i].strip()
253  args = []
254  rest = typ[i + 1:-1].strip()
255  while rest:
256  i = util.find_comma(rest)
257  if i == -1:
258  a, rest = rest, ''
259  else:
260  a, rest = rest[:i].rstrip(), rest[i + 1:].lstrip()
261  args.append(cls.parse(a))
262  args = tuple(args)
263 
264  name = util.translate_map.get(name, name)
265  return cls(name, args)
std::string strip(std::string_view str)
trim any whitespace from the left and right ends of a string
std::string join(T const &container, std::string const &delim)