Partially sync files.el from XEmacs 21.5 for wildcard support.
[sxemacs] / src / category.h
1 /*** category.h -- categorial view on objects, this is NOT OO
2  *
3  * Copyright (C) 2008 Sebastian Freundt
4  *
5  * Author:  Sebastian Freundt <hroptatyr@sxemacs.org>
6  *
7  * This file is part of SXEmacs.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * 3. Neither the name of the author nor the names of any contributors
21  *    may be used to endorse or promote products derived from this
22  *    software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  ***/
37
38 #ifndef INCLUDED_category_h_
39 #define INCLUDED_category_h_
40
41 #include "lrecord.h"
42
43 enum cat_morphism_kind_e {
44         cat_mk_none = -1,
45         cat_mk_lc = 0,          /* whether or not lcrecord header is used */
46         cat_mk_seq,
47         cat_mk_set,
48         cat_mk_aseq,            /* associative seqs */
49         cat_mk_aset,            /* associative sets aka dicts */
50         number_of_cat_morphism_kinds,
51 };
52
53 typedef struct cat_morphism_s *cat_morphism_t;
54 typedef enum cat_morphism_kind_e cat_morphism_kind_t;
55
56 extern_inline bool __bit_set_p(int number, char bit);
57 extern_inline char __nbits_right_of(int number, char bit);
58 extern cat_morphism_t morphisms;
59
60 \f
61 /* a double lookup approach
62  * this is the complete list of morphisms (views) that an object can have */
63 struct cat_morphism_s {
64         void *seq_impl;
65         void *set_impl;
66         void *aseq_impl;
67         void *aset_impl;
68 };
69
70
71 struct __cat_morphism_lrec_s {
72         struct lrecord_header lh;
73         void *foo;
74 };
75
76 struct __cat_morphism_lcrec_s {
77         struct lcrecord_header lch;
78         void *foo;
79 };
80
81 /* inlines */
82 extern_inline bool
83 __bit_set_p(int number, char bit)
84 {
85 /* return whether bit BIT is set in NUMBER
86  * (10010101, 5) => t
87  * the right most bit has bit number 0 */
88         return ((1<<bit) & number) != 0;
89 }
90
91 #if defined HAVE_ASM_EAX && defined HAVE_ASM_CL &&      \
92         defined HAVE_ASM_ADCB && defined HAVE_ASM_SARL
93 extern_inline char
94 __nbits_right_of(int number, char bit)
95 {
96 /* return the number of set bits in NUMBER right of BIT
97  * (10010101, 4) => 2
98  * bit count starts at 0 and on the right */
99         /* we just stuff `BIT' into CNT which goes to cx */
100         register char cnt = bit;
101
102         __asm__ volatile (
103 #if !defined HAVE_ASM_RETVAL_IN_EBX
104                 "       pushl %%ebx             /* save EBX ([nmsk]) */\n"
105 #endif  /* HAVE_ASM_RETVAL_IN_EBX */
106                 /* initialise AX directly */
107                 "       movl $1, %%eax\n"
108                 "       sall %[cnt], %%eax      /* CL has value of BIT */\n"
109                 "       subl $1, %%eax\n"
110                 "       andl %%eax, %[nmsk]     /* nmsk <- 1<<bit - 1*/\n"
111                 "       xorb %[cnt], %[cnt]     /* cnt <- 0 */\n"
112                 /* main body */
113                 "\n"
114                 "       sarl $1, %[nmsk]        /* shift right and */\n"
115                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
116                 "\n"
117                 "       sarl $1, %[nmsk]        /* shift right and */\n"
118                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
119                 "\n"
120                 "       sarl $1, %[nmsk]        /* shift right and */\n"
121                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
122                 "\n"
123                 "       sarl $1, %[nmsk]        /* shift right and */\n"
124                 /* maybe %[nmsk] is zero meanwhile, check for it and
125                  * return if so */
126                 "       jz 0f\n"
127                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
128                 "\n"
129                 "       sarl $1, %[nmsk]        /* shift right and */\n"
130                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
131                 "\n"
132                 "       sarl $1, %[nmsk]        /* shift right and */\n"
133                 /* maybe %[nmsk] is zero meanwhile, check for it and
134                  * return if so */
135                 "       jz 0f\n"
136                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
137                 "\n"
138                 "       sarl $1, %[nmsk]        /* shift right and */\n"
139                 /* maybe %[nmsk] is zero meanwhile, check for it and
140                  * return if so */
141                 "       jz 0f\n"
142                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
143                 "\n"
144                 "       sarl $1, %[nmsk]        /* shift right and */\n"
145                 "0:\n"
146                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
147 #if !defined HAVE_ASM_RETVAL_IN_EBX
148                 "       popl %%ebx              /* restore EBX */\n"
149 #endif
150                 : [cnt] "+c" (cnt) /* <- bit is in here */
151                 : [nmsk] "d" (number)
152                 : "%eax", "cc");
153         return cnt;
154 }
155 #else  /* !all the above */
156 extern_inline char
157 __nbits_right_of(int number, char bit)
158 {
159   register char cnt = 0;
160   register unsigned n;
161   for(n = number & ((1<<bit)-1); n ; n >>= 1)
162     if( n%2 ) cnt++;
163   return cnt;
164 }
165 #endif
166
167 #if 1                           /* using the global shit */
168 static inline void*const*
169 cat_morphisms(const void *obj)
170 {
171 /* returns a pointer to the array of implementations or
172  * NULL if there are none */
173         if (((const struct lrecord_header*)obj)->morphisms & cat_mk_lc) {
174                 return &((const struct __cat_morphism_lcrec_s*)obj)->foo;
175         } else {
176                 return &((const struct __cat_morphism_lrec_s*)obj)->foo;
177         }
178 }
179
180 static inline void*
181 cat_morphism(const void *obj, cat_morphism_kind_t kind)
182 {
183         unsigned int flags = ((const struct lrecord_header*)obj)->morphisms;
184
185         if (!__bit_set_p(flags, kind)) {
186                 int type = ((const struct lrecord_header*)obj)->type;
187                 switch (kind) {
188                 case cat_mk_seq:
189                         return morphisms[type].seq_impl;
190                 case cat_mk_set:
191                         return morphisms[type].set_impl;
192                 case cat_mk_aseq:
193                         return morphisms[type].aseq_impl;
194                 case cat_mk_aset:
195                         return morphisms[type].aset_impl;
196                         /* list them all here */
197                 case cat_mk_none:
198                 case cat_mk_lc:
199                 case number_of_cat_morphism_kinds:
200                 default:
201                         return NULL;
202                 }
203         } else {
204                 void *const*mph = cat_morphisms(obj);
205                 return mph[__nbits_right_of(flags, kind)-(flags&1)];
206         }
207 }
208 #else  /* use definition in category.c */
209 extern void *cat_morphism(const void*, cat_morphism_kind_t);
210 extern void *const*cat_morphisms(const void*);
211 #endif
212 #endif  /* INCLUDED_category_h_ */