Initial git import
[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_inline void *cat_morphism(const void*, cat_morphism_kind_t);
59 extern_inline void *const*cat_morphisms(const void*);
60 extern cat_morphism_t morphisms;
61
62 \f
63 /* a double lookup approach
64  * this is the complete list of morphisms (views) that an object can have */
65 struct cat_morphism_s {
66         void *seq_impl;
67         void *set_impl;
68         void *aseq_impl;
69         void *aset_impl;
70 };
71
72
73 struct __cat_morphism_lrec_s {
74         struct lrecord_header lh;
75         void *foo;
76 };
77
78 struct __cat_morphism_lcrec_s {
79         struct lcrecord_header lch;
80         void *foo;
81 };
82
83 /* inlines */
84 extern_inline bool
85 __bit_set_p(int number, char bit)
86 {
87 /* return whether bit BIT is set in NUMBER
88  * (10010101, 5) => t
89  * the right most bit has bit number 0 */
90         return ((1<<bit) & number) != 0;
91 }
92
93 #if defined HAVE_ASM_EAX && defined HAVE_ASM_CL &&      \
94         defined HAVE_ASM_ADCB && defined HAVE_ASM_SARL
95 extern_inline char
96 __nbits_right_of(int number, char bit)
97 {
98 /* return the number of set bits in NUMBER right of BIT
99  * (10010101, 4) => 2
100  * bit count starts at 0 and on the right */
101         /* we just stuff `BIT' into CNT which goes to cx */
102         register char cnt = bit;
103
104         __asm__ volatile (
105 #if !defined HAVE_ASM_RETVAL_IN_EBX
106                 "       pushl %%ebx             /* save EBX ([nmsk]) */\n"
107 #endif  /* HAVE_ASM_RETVAL_IN_EBX */
108                 /* initialise AX directly */
109                 "       movl $1, %%eax\n"
110                 "       sall %[cnt], %%eax      /* CL has value of BIT */\n"
111                 "       subl $1, %%eax\n"
112                 "       andl %%eax, %[nmsk]     /* nmsk <- 1<<bit - 1*/\n"
113                 "       xorb %[cnt], %[cnt]     /* cnt <- 0 */\n"
114                 /* main body */
115                 "\n"
116                 "       sarl $1, %[nmsk]        /* shift right and */\n"
117                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
118                 "\n"
119                 "       sarl $1, %[nmsk]        /* shift right and */\n"
120                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
121                 "\n"
122                 "       sarl $1, %[nmsk]        /* shift right and */\n"
123                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
124                 "\n"
125                 "       sarl $1, %[nmsk]        /* shift right and */\n"
126                 /* maybe %[nmsk] is zero meanwhile, check for it and
127                  * return if so */
128                 "       jz 0f\n"
129                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
130                 "\n"
131                 "       sarl $1, %[nmsk]        /* shift right and */\n"
132                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
133                 "\n"
134                 "       sarl $1, %[nmsk]        /* shift right and */\n"
135                 /* maybe %[nmsk] is zero meanwhile, check for it and
136                  * return if so */
137                 "       jz 0f\n"
138                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
139                 "\n"
140                 "       sarl $1, %[nmsk]        /* shift right and */\n"
141                 /* maybe %[nmsk] is zero meanwhile, check for it and
142                  * return if so */
143                 "       jz 0f\n"
144                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
145                 "\n"
146                 "       sarl $1, %[nmsk]        /* shift right and */\n"
147                 "0:\n"
148                 "       adcb $0, %[cnt]         /* add 1 if carry was set*/\n"
149 #if !defined HAVE_ASM_RETVAL_IN_EBX
150                 "       popl %%ebx              /* restore EBX */\n"
151 #endif
152                 : [cnt] "+c" (cnt) /* <- bit is in here */
153                 : [nmsk] "d" (number)
154                 : "%eax", "cc");
155         return cnt;
156 }
157 #else  /* !all the above */
158 extern_inline char
159 __nbits_right_of(int number, char bit)
160 {
161   register char cnt = 0;
162   register unsigned n;
163   for(n = number & ((1<<bit)-1); n ; n >>= 1)
164     if( n%2 ) cnt++;
165   return cnt;
166 }
167 #endif
168
169 #if 1                           /* using the global shit */
170 extern_inline void*const*
171 cat_morphisms(const void *obj)
172 {
173 /* returns a pointer to the array of implementations or
174  * NULL if there are none */
175         if (((const struct lrecord_header*)obj)->morphisms & cat_mk_lc) {
176                 return &((const struct __cat_morphism_lcrec_s*)obj)->foo;
177         } else {
178                 return &((const struct __cat_morphism_lrec_s*)obj)->foo;
179         }
180 }
181
182 extern_inline void*
183 cat_morphism(const void *obj, cat_morphism_kind_t kind)
184 {
185         unsigned int flags = ((const struct lrecord_header*)obj)->morphisms;
186
187         if (!__bit_set_p(flags, kind)) {
188                 int type = ((const struct lrecord_header*)obj)->type;
189                 switch (kind) {
190                 case cat_mk_seq:
191                         return morphisms[type].seq_impl;
192                 case cat_mk_set:
193                         return morphisms[type].set_impl;
194                 case cat_mk_aseq:
195                         return morphisms[type].aseq_impl;
196                 case cat_mk_aset:
197                         return morphisms[type].aset_impl;
198                         /* list them all here */
199                 case cat_mk_none:
200                 case cat_mk_lc:
201                 case number_of_cat_morphism_kinds:
202                 default:
203                         return NULL;
204                 }
205         } else {
206                 void *const*mph = cat_morphisms(obj);
207                 return mph[__nbits_right_of(flags, kind)-(flags&1)];
208         }
209 }
210 #endif
211 #endif  /* INCLUDED_category_h_ */