5959# a member function or free function
6060ITEM_TYPE_FUNCTION = 2
6161
62+ # a constructor
63+ ITEM_TYPE_CONSTRUCTOR = 3
64+
65+ # a constructor that is described in the same page as the class
66+ ITEM_TYPE_CONSTRUCTOR_INLINEMEM = 4
67+
68+ # a destructor
69+ ITEM_TYPE_DESTRUCTOR = 5
70+
71+ # a destructor that is described in the same page as the class
72+ ITEM_TYPE_DESTRUCTOR_INLINEMEM = 6
73+
6274# a member function that is described in the same page as the class
63- ITEM_TYPE_FUNCTION_INLINEMEM = 3
75+ ITEM_TYPE_FUNCTION_INLINEMEM = 7
6476
6577# an enum
66- ITEM_TYPE_ENUM = 4
78+ ITEM_TYPE_ENUM = 8
6779
6880# a value of an enum
69- ITEM_TYPE_ENUM_CONST = 5
81+ ITEM_TYPE_ENUM_CONST = 9
7082
7183def get_item_type (el ):
7284 if (el .tag == 'const' and el .getparent ().tag == 'enum' and
@@ -77,6 +89,16 @@ def get_item_type(el):
7789 return ITEM_TYPE_FUNCTION_INLINEMEM
7890 else :
7991 return ITEM_TYPE_FUNCTION
92+ if el .tag == 'constructor' :
93+ if el .get ('link' ) == '.' :
94+ return ITEM_TYPE_CONSTRUCTOR_INLINEMEM
95+ else :
96+ return ITEM_TYPE_CONSTRUCTOR
97+ if el .tag == 'destructor' :
98+ if el .get ('link' ) == '.' :
99+ return ITEM_TYPE_DESTRUCTOR_INLINEMEM
100+ else :
101+ return ITEM_TYPE_DESTRUCTOR
80102 if el .tag == 'class' :
81103 return ITEM_TYPE_CLASS
82104 if el .tag == 'enum' :
@@ -219,6 +241,135 @@ def build_abstract(decls, desc):
219241
220242 return all_code + desc
221243
244+ ''' Outputs additional redirects for an identifier.
245+
246+ Firstly, we replace '::' with spaces. Then we add two redirects: one with
247+ unchanged text and another with '_' replaced with spaces. We strip one
248+ level of namespace/class qualification and repeat the process with the
249+ remaining text.
250+
251+ For constructors and destructors, we strip the function name and apply the
252+ abovementioned algorithm, the only difference being that we append
253+ (or prepend) 'constructor' or 'destructor' to the title of the redirect
254+ respectively.
255+
256+ Each redirect has a 'priority', which is defined by the number of stripped
257+ namespace/class qualifications from the entry that produced the redirect.
258+ This is used to remove duplicate redirects. For each group of duplicate
259+ redirects, we find the redirect with the highest priority (i.e. lowest
260+ number of qualifications stripped) and remove all other redirects. If the
261+ number of highest-priority redirects is more than one, then we remove all
262+ redirects from the group altogether.
263+
264+ We don't add any redirects to specializations, overloads or operators.
265+ '''
266+ ''' array of dict { 'title' -> redirect title,
267+ 'target' -> redirect target,
268+ 'priority' -> redirect priority as int
269+ }
270+ '''
271+ redirects = []
272+
273+ def build_redirects (item_ident , item_type ):
274+ global redirects
275+
276+ for ch in [ '(' , ')' , '<' , '>' , 'operator' ]:
277+ if ch in item_ident :
278+ return
279+
280+ target = item_ident
281+ parts = item_ident .split ('::' )
282+
283+ # -----
284+ def do_parts (parts , prepend = '' , append = '' ):
285+ global redirects
286+ if prepend != '' :
287+ prepend = prepend + ' '
288+ if append != '' :
289+ append = ' ' + append
290+
291+ p = 0
292+ while p < len (parts ):
293+ redir1 = prepend + ' ' .join (parts [p :]) + append
294+ redir2 = prepend + ' ' .join (x .replace ('_' ,' ' ) for x in parts [p :]) + append
295+
296+ redir1 = redir1 .replace (' ' , ' ' ).replace (' ' , ' ' )
297+ redir2 = redir2 .replace (' ' , ' ' ).replace (' ' , ' ' )
298+
299+ redirects .append ({'title' : redir1 , 'target' : target ,
300+ 'priority' : p })
301+ if redir1 != redir2 :
302+ redirects .append ({'title' : redir2 , 'target' : target ,
303+ 'priority' : p })
304+ p += 1
305+ # -----
306+
307+ if item_type in [ ITEM_TYPE_CLASS ,
308+ ITEM_TYPE_FUNCTION ,
309+ ITEM_TYPE_FUNCTION_INLINEMEM ,
310+ ITEM_TYPE_ENUM ,
311+ ITEM_TYPE_ENUM_CONST ]:
312+ do_parts (parts )
313+
314+ elif item_type in [ ITEM_TYPE_CONSTRUCTOR ,
315+ ITEM_TYPE_CONSTRUCTOR_INLINEMEM ]:
316+ parts .pop ()
317+ do_parts (parts , prepend = 'constructor' )
318+ do_parts (parts , append = 'constructor' )
319+ elif item_type in [ ITEM_TYPE_DESTRUCTOR ,
320+ ITEM_TYPE_DESTRUCTOR_INLINEMEM ]:
321+ parts .pop ()
322+ do_parts (parts , prepend = 'destructor' )
323+ do_parts (parts , append = 'destructor' )
324+ else :
325+ pass # should not be here
326+
327+ def output_redirects ():
328+ global redirects
329+
330+ # convert to a convenient data structure
331+ # dict { title -> dict { priority -> list ( targets ) } }
332+ redir_map = {}
333+
334+ for r in redirects :
335+ title = r ['title' ]
336+ target = r ['target' ]
337+ priority = r ['priority' ]
338+
339+ if title not in redir_map :
340+ redir_map [title ] = {}
341+ if priority not in redir_map [title ]:
342+ redir_map [title ][priority ] = []
343+
344+ redir_map [title ][priority ].append (target )
345+
346+ # get non-duplicate redirects
347+ ok_redirects = [] # list ( dict { 'title' : title, 'target' : target })
348+
349+ for title in redir_map :
350+ # priority decreases with increasing values
351+ highest_prio = min (redir_map [title ])
352+ if len (redir_map [title ][highest_prio ]) == 1 :
353+ # not duplicate
354+ target = redir_map [title ][highest_prio ][0 ]
355+ ok_redirects .append ({ 'title' : title , 'target' : target })
356+
357+ # sort the redirects
358+ ok_redirects = sorted (ok_redirects , key = lambda x : x ['title' ])
359+
360+ # output
361+ for r in ok_redirects :
362+ # title
363+ line = r ['title' ] + '\t '
364+ # type
365+ line += 'R\t '
366+ # redirect
367+ line += r ['target' ] + '\t '
368+ # otheruses, categories, references, see_also, further_reading,
369+ # external links, disambiguation, images, abstract, source url
370+ line += '\t \t \t \t \t \t \t \t \t \t \n '
371+ out .write (line )
372+
222373if debug :
223374 out = sys .stdout
224375else :
@@ -258,12 +409,16 @@ def build_abstract(decls, desc):
258409 desc = get_short_description (root , get_version (decls ), debug = debug_verbose )
259410 abstract = build_abstract (decls , desc )
260411
261- elif item_type == ITEM_TYPE_FUNCTION :
412+ elif item_type in [ ITEM_TYPE_FUNCTION ,
413+ ITEM_TYPE_CONSTRUCTOR ,
414+ ITEM_TYPE_DESTRUCTOR ]:
262415 decls = get_declarations (root , name )
263416 desc = get_short_description (root , get_version (decls ), debug = debug_verbose )
264417 abstract = build_abstract (decls , desc )
265418
266- elif item_type == ITEM_TYPE_FUNCTION_INLINEMEM :
419+ elif item_type in [ ITEM_TYPE_FUNCTION_INLINEMEM ,
420+ ITEM_TYPE_CONSTRUCTOR_INLINEMEM ,
421+ ITEM_TYPE_DESTRUCTOR_INLINEMEM ]:
267422 raise DdgException ("INLINEMEM" ) # not implemented
268423 ''' Implementation notes:
269424 * the declarations are possibly versioned
@@ -301,11 +456,16 @@ def build_abstract(decls, desc):
301456 # source url
302457 line += 'http://en.cppreference.com/w/' + link + '\n '
303458 out .write (line )
459+
460+ build_redirects (item_ident , item_type )
461+
304462 except DdgException as err :
305463 if debug :
306464 line = '# error (' + str (err ) + "): " + link + ": " + item_ident + "\n "
307465 out .write (line )
308466
467+ output_redirects ()
468+
309469if debug :
310470 print ('=============================' )
311471 print ('Numbers of lines used:' )
0 commit comments