diff options
| author | Daniel Colascione | 2013-09-22 01:31:55 -0800 |
|---|---|---|
| committer | Daniel Colascione | 2013-09-22 01:31:55 -0800 |
| commit | 3e0b94e7ff1fc69b077322d672ef5d0b668541c3 (patch) | |
| tree | 9927abd073960f2460f05a43ae9467cd82c00b9b /src/data.c | |
| parent | 76880d884d87d0bc674249e292ccda70f31cca0e (diff) | |
| download | emacs-3e0b94e7ff1fc69b077322d672ef5d0b668541c3.tar.gz emacs-3e0b94e7ff1fc69b077322d672ef5d0b668541c3.zip | |
Add set operations for bool-vector.
http://lists.gnu.org/archive/html/emacs-devel/2013-09/msg00404.html
* data.c (Qbool_vector_p): New symbol.
(bool_vector_spare_mask,popcount_size_t_generic)
(popcount_size_t_msc,popcount_size_t_gcc)
(popcount_size_t)
(bool_vector_binop_driver)
(count_trailing_zero_bits,size_t_to_host_endian)
(Fbool_vector_exclusive_or)
(Fbool_vector_union)
(Fbool_vector_intersection,Fbool_vector_set_difference)
(Fbool_vector_subsetp,Fbool_vector_not)
(Fbool_vector_count_matches)
(Fbool_vector_count_matches_at): New functions.
(syms_of_data): Intern new symbol, functions.
* alloc.c (bool_vector_payload_bytes): New function.
(Fmake_bool_vector): Instead of calling Fmake_vector,
which performs redundant initialization and argument checking,
just call allocate_vector ourselves. Make sure we clear any
terminating padding to zero.
(vector_nbytes,sweep_vectors): Use bool_vector_payload_bytes
instead of open-coding the size calculation.
(vroundup_ct): New macro.
(vroundup): Assume argument >= 0; invoke vroundup_ct.
* casetab.c (shuffle,set_identity): Change lint_assume to assume.
* composite.c (composition_gstring_put_cache): Change
lint_assume to assume.
* conf_post.h (assume): New macro.
(lint_assume): Remove.
* dispnew.c (update_frame_1): Change lint_assume to assume.
* ftfont.c (ftfont_shape_by_flt): Change lint_assume
to assume.
* image.c (gif_load): Change lint_assume to assume.
* lisp.h (eassert_and_assume): New macro.
(Qbool_vector_p): Declare.
(CHECK_BOOL_VECTOR,ROUNDUP,BITS_PER_SIZE_T): New macros.
(swap16,swap32,swap64): New inline functions.
* macfont.c (macfont_shape): Change lint_assume to assume.
* ralloc.c: Rename ROUNDUP to PAGE_ROUNDUP throughout.
* xsettings.c (parse_settings): Use new swap16 and
swap32 from lisp.h instead of file-specific macros.
Diffstat (limited to 'src/data.c')
| -rw-r--r-- | src/data.c | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/src/data.c b/src/data.c index 51b0266eca1..5a05e0652ad 100644 --- a/src/data.c +++ b/src/data.c | |||
| @@ -54,6 +54,7 @@ Lisp_Object Qintegerp, Qwholenump, Qsymbolp, Qlistp, Qconsp; | |||
| 54 | static Lisp_Object Qnatnump; | 54 | static Lisp_Object Qnatnump; |
| 55 | Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; | 55 | Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; |
| 56 | Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; | 56 | Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; |
| 57 | Lisp_Object Qbool_vector_p; | ||
| 57 | Lisp_Object Qbuffer_or_string_p; | 58 | Lisp_Object Qbuffer_or_string_p; |
| 58 | static Lisp_Object Qkeywordp, Qboundp; | 59 | static Lisp_Object Qkeywordp, Qboundp; |
| 59 | Lisp_Object Qfboundp; | 60 | Lisp_Object Qfboundp; |
| @@ -2956,6 +2957,457 @@ lowercase l) for small endian machines. */) | |||
| 2956 | return make_number (order); | 2957 | return make_number (order); |
| 2957 | } | 2958 | } |
| 2958 | 2959 | ||
| 2960 | /* Because we round up the bool vector allocate size to word_size | ||
| 2961 | units, we can safely read past the "end" of the vector in the | ||
| 2962 | operations below. These extra bits are always zero. Also, we | ||
| 2963 | always allocate bool vectors with at least one size_t of storage so | ||
| 2964 | that we don't have to special-case empty bit vectors. */ | ||
| 2965 | |||
| 2966 | static inline | ||
| 2967 | size_t | ||
| 2968 | bool_vector_spare_mask (ptrdiff_t nr_bits) | ||
| 2969 | { | ||
| 2970 | eassert_and_assume (nr_bits > 0); | ||
| 2971 | return (((size_t) 1) << (nr_bits % BITS_PER_SIZE_T)) - 1; | ||
| 2972 | } | ||
| 2973 | |||
| 2974 | #if __MSC_VER >= 1500 && (defined _M_IX86 || defined _M_X64) | ||
| 2975 | # define USE_MSC_POPCOUNT | ||
| 2976 | #elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) | ||
| 2977 | # define USE_GCC_POPCOUNT | ||
| 2978 | #else | ||
| 2979 | # define NEED_GENERIC_POPCOUNT | ||
| 2980 | #endif | ||
| 2981 | |||
| 2982 | #ifdef USE_MSC_POPCOUNT | ||
| 2983 | #define NEED_GENERIC_POPCOUNT | ||
| 2984 | #endif | ||
| 2985 | |||
| 2986 | #ifdef NEED_GENERIC_POPCOUNT | ||
| 2987 | static inline | ||
| 2988 | unsigned int | ||
| 2989 | popcount_size_t_generic (size_t val) | ||
| 2990 | { | ||
| 2991 | unsigned short j; | ||
| 2992 | unsigned int count = 0; | ||
| 2993 | |||
| 2994 | for (j = 0; j < BITS_PER_SIZE_T; ++j) | ||
| 2995 | count += !!((((size_t) 1) << j) & val); | ||
| 2996 | |||
| 2997 | return count; | ||
| 2998 | } | ||
| 2999 | #endif | ||
| 3000 | |||
| 3001 | #ifdef USE_MSC_POPCOUNT | ||
| 3002 | static inline | ||
| 3003 | unsigned int | ||
| 3004 | popcount_size_t_msc (size_t val) | ||
| 3005 | { | ||
| 3006 | unsigned int count; | ||
| 3007 | |||
| 3008 | #pragma intrinsic __cpuid | ||
| 3009 | /* While gcc falls back to its own generic code if the machine on | ||
| 3010 | which it's running doesn't support popcount, we need to perform the | ||
| 3011 | detection and fallback ourselves when compiling with Microsoft's | ||
| 3012 | compiler. */ | ||
| 3013 | |||
| 3014 | static enum { | ||
| 3015 | popcount_unknown_support, | ||
| 3016 | popcount_use_generic, | ||
| 3017 | popcount_use_intrinsic | ||
| 3018 | } popcount_state; | ||
| 3019 | |||
| 3020 | if (popcount_state == popcount_unknown_support) | ||
| 3021 | { | ||
| 3022 | int cpu_info[4]; | ||
| 3023 | __cpuid (cpu_info, 1); | ||
| 3024 | if (cpu_info[2] & (1<<23)) /* See MSDN. */ | ||
| 3025 | popcount_state = popcount_use_intrinsic; | ||
| 3026 | else | ||
| 3027 | popcount_state = popcount_use_generic; | ||
| 3028 | } | ||
| 3029 | |||
| 3030 | if (popcount_state == popcount_use_intrinsic) | ||
| 3031 | { | ||
| 3032 | # if BITS_PER_SIZE_T == 64 | ||
| 3033 | # pragma intrinsic __popcnt64 | ||
| 3034 | count = __popcnt64 (val); | ||
| 3035 | # else | ||
| 3036 | # pragma intrinsic __popcnt | ||
| 3037 | count = __popcnt (val); | ||
| 3038 | # endif | ||
| 3039 | } | ||
| 3040 | else | ||
| 3041 | count = popcount_size_t_generic (val); | ||
| 3042 | |||
| 3043 | return count; | ||
| 3044 | } | ||
| 3045 | #endif /* USE_MSC_POPCOUNT */ | ||
| 3046 | |||
| 3047 | #ifdef USE_GCC_POPCOUNT | ||
| 3048 | static inline | ||
| 3049 | unsigned int | ||
| 3050 | popcount_size_t_gcc (size_t val) | ||
| 3051 | { | ||
| 3052 | # if BITS_PER_SIZE_T == 64 | ||
| 3053 | return __builtin_popcountll (val); | ||
| 3054 | # else | ||
| 3055 | return __builtin_popcount (val); | ||
| 3056 | # endif | ||
| 3057 | } | ||
| 3058 | #endif /* USE_GCC_POPCOUNT */ | ||
| 3059 | |||
| 3060 | static inline | ||
| 3061 | unsigned int | ||
| 3062 | popcount_size_t(size_t val) | ||
| 3063 | { | ||
| 3064 | #if defined USE_MSC_POPCOUNT | ||
| 3065 | return popcount_size_t_msc (val); | ||
| 3066 | #elif defined USE_GCC_POPCOUNT | ||
| 3067 | return popcount_size_t_gcc (val); | ||
| 3068 | #else | ||
| 3069 | return popcount_size_t_generic (val); | ||
| 3070 | #endif | ||
| 3071 | } | ||
| 3072 | |||
| 3073 | enum bool_vector_op { bool_vector_exclusive_or, | ||
| 3074 | bool_vector_union, | ||
| 3075 | bool_vector_intersection, | ||
| 3076 | bool_vector_set_difference, | ||
| 3077 | bool_vector_subsetp }; | ||
| 3078 | |||
| 3079 | static inline | ||
| 3080 | Lisp_Object | ||
| 3081 | bool_vector_binop_driver (Lisp_Object op1, | ||
| 3082 | Lisp_Object op2, | ||
| 3083 | Lisp_Object dest, | ||
| 3084 | enum bool_vector_op op) | ||
| 3085 | { | ||
| 3086 | EMACS_INT nr_bits; | ||
| 3087 | size_t *adata, *bdata, *cdata; | ||
| 3088 | ptrdiff_t i; | ||
| 3089 | size_t changed = 0; | ||
| 3090 | size_t mword; | ||
| 3091 | ptrdiff_t nr_words; | ||
| 3092 | |||
| 3093 | CHECK_BOOL_VECTOR (op1); | ||
| 3094 | CHECK_BOOL_VECTOR (op2); | ||
| 3095 | |||
| 3096 | nr_bits = min (XBOOL_VECTOR (op1)->size, | ||
| 3097 | XBOOL_VECTOR (op2)->size); | ||
| 3098 | |||
| 3099 | if (NILP (dest)) | ||
| 3100 | { | ||
| 3101 | dest = Fmake_bool_vector (make_number (nr_bits), Qnil); | ||
| 3102 | changed = 1; | ||
| 3103 | } | ||
| 3104 | else | ||
| 3105 | { | ||
| 3106 | CHECK_BOOL_VECTOR (dest); | ||
| 3107 | nr_bits = min (nr_bits, XBOOL_VECTOR (dest)->size); | ||
| 3108 | } | ||
| 3109 | |||
| 3110 | eassert_and_assume (nr_bits >= 0); | ||
| 3111 | nr_words = ROUNDUP(nr_bits, BITS_PER_SIZE_T) / BITS_PER_SIZE_T; | ||
| 3112 | |||
| 3113 | adata = (size_t*) XBOOL_VECTOR (dest)->data; | ||
| 3114 | bdata = (size_t*) XBOOL_VECTOR (op1)->data; | ||
| 3115 | cdata = (size_t*) XBOOL_VECTOR (op2)->data; | ||
| 3116 | i = 0; | ||
| 3117 | do | ||
| 3118 | { | ||
| 3119 | if (op == bool_vector_exclusive_or) | ||
| 3120 | mword = bdata[i] ^ cdata[i]; | ||
| 3121 | else if (op == bool_vector_union || op == bool_vector_subsetp) | ||
| 3122 | mword = bdata[i] | cdata[i]; | ||
| 3123 | else if (op == bool_vector_intersection) | ||
| 3124 | mword = bdata[i] & cdata[i]; | ||
| 3125 | else if (op == bool_vector_set_difference) | ||
| 3126 | mword = bdata[i] &~ cdata[i]; | ||
| 3127 | else | ||
| 3128 | abort (); | ||
| 3129 | |||
| 3130 | changed |= adata[i] ^ mword; | ||
| 3131 | |||
| 3132 | if (op != bool_vector_subsetp) | ||
| 3133 | adata[i] = mword; | ||
| 3134 | |||
| 3135 | i += 1; | ||
| 3136 | } | ||
| 3137 | while (i < nr_words); | ||
| 3138 | return changed ? dest : Qnil; | ||
| 3139 | } | ||
| 3140 | |||
| 3141 | /* Compute the number of trailing zero bits in val. If val is zero, | ||
| 3142 | return the number of bits in val. */ | ||
| 3143 | static inline | ||
| 3144 | unsigned int | ||
| 3145 | count_trailing_zero_bits (size_t val) | ||
| 3146 | { | ||
| 3147 | if (val == 0) | ||
| 3148 | return CHAR_BIT * sizeof (val); | ||
| 3149 | |||
| 3150 | #if defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 64 | ||
| 3151 | return __builtin_ctzll (val); | ||
| 3152 | #elif defined USE_GCC_POPCOUNT && BITS_PER_SIZE_T == 32 | ||
| 3153 | return __builtin_ctz (val); | ||
| 3154 | #elif __MSC_VER && BITS_PER_SIZE_T == 64 | ||
| 3155 | # pragma intrinsic _BitScanForward64 | ||
| 3156 | { | ||
| 3157 | /* No support test needed: support since 386. */ | ||
| 3158 | unsigned long result; | ||
| 3159 | _BitScanForward64 (&result, val); | ||
| 3160 | return (unsigned int) result; | ||
| 3161 | } | ||
| 3162 | #elif __MSC_VER && BITS_PER_SIZE_T == 32 | ||
| 3163 | # pragma intrinsic _BitScanForward | ||
| 3164 | { | ||
| 3165 | /* No support test needed: support since 386. */ | ||
| 3166 | unsigned long result; | ||
| 3167 | _BitScanForward (&result, val); | ||
| 3168 | return (unsigned int) result; | ||
| 3169 | } | ||
| 3170 | #else | ||
| 3171 | { | ||
| 3172 | unsigned int count; | ||
| 3173 | count = 0; | ||
| 3174 | for(val = ~val; val & 1; val >>= 1) | ||
| 3175 | ++count; | ||
| 3176 | |||
| 3177 | return count; | ||
| 3178 | } | ||
| 3179 | #endif | ||
| 3180 | } | ||
| 3181 | |||
| 3182 | static inline | ||
| 3183 | size_t | ||
| 3184 | size_t_to_host_endian (size_t val) | ||
| 3185 | { | ||
| 3186 | #ifdef WORDS_BIGENDIAN | ||
| 3187 | # if BITS_PER_SIZE_T == 64 | ||
| 3188 | return swap64 (val); | ||
| 3189 | # else | ||
| 3190 | return swap32 (val); | ||
| 3191 | # endif | ||
| 3192 | #else | ||
| 3193 | return val; | ||
| 3194 | #endif | ||
| 3195 | } | ||
| 3196 | |||
| 3197 | DEFUN ("bool-vector-exclusive-or", Fbool_vector_exclusive_or, | ||
| 3198 | Sbool_vector_exclusive_or, 2, 3, 0, | ||
| 3199 | doc: /* Compute C = A ^ B, bitwise exclusive or. | ||
| 3200 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3201 | vector in which to store the result. Return the destination vector if | ||
| 3202 | it changed or nil otherwise. */ | ||
| 3203 | ) | ||
| 3204 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3205 | { | ||
| 3206 | return bool_vector_binop_driver (a, b, c, bool_vector_exclusive_or); | ||
| 3207 | } | ||
| 3208 | |||
| 3209 | DEFUN ("bool-vector-union", Fbool_vector_union, | ||
| 3210 | Sbool_vector_union, 2, 3, 0, | ||
| 3211 | doc: /* Compute C = A | B, bitwise or. | ||
| 3212 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3213 | vector in which to store the result. Return the destination vector if | ||
| 3214 | it changed or nil otherwise. */) | ||
| 3215 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3216 | { | ||
| 3217 | return bool_vector_binop_driver (a, b, c, bool_vector_union); | ||
| 3218 | } | ||
| 3219 | |||
| 3220 | DEFUN ("bool-vector-intersection", Fbool_vector_intersection, | ||
| 3221 | Sbool_vector_intersection, 2, 3, 0, | ||
| 3222 | doc: /* Compute C = A & B, bitwise and. | ||
| 3223 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3224 | vector in which to store the result. Return the destination vector if | ||
| 3225 | it changed or nil otherwise. */) | ||
| 3226 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3227 | { | ||
| 3228 | return bool_vector_binop_driver (a, b, c, bool_vector_intersection); | ||
| 3229 | } | ||
| 3230 | |||
| 3231 | DEFUN ("bool-vector-set-difference", Fbool_vector_set_difference, | ||
| 3232 | Sbool_vector_set_difference, 2, 3, 0, | ||
| 3233 | doc: /* Compute C = A &~ B, set difference. | ||
| 3234 | A, B, and C must be bool vectors. If C is nil, allocate a new bool | ||
| 3235 | vector in which to store the result. Return the destination vector if | ||
| 3236 | it changed or nil otherwise. */) | ||
| 3237 | (Lisp_Object a, Lisp_Object b, Lisp_Object c) | ||
| 3238 | { | ||
| 3239 | return bool_vector_binop_driver (a, b, c, bool_vector_set_difference); | ||
| 3240 | } | ||
| 3241 | |||
| 3242 | DEFUN ("bool-vector-subsetp", Fbool_vector_subsetp, | ||
| 3243 | Sbool_vector_subsetp, 2, 2, 0, | ||
| 3244 | doc: ) | ||
| 3245 | (Lisp_Object a, Lisp_Object b) | ||
| 3246 | { | ||
| 3247 | /* Like bool_vector_union, but doesn't modify b. */ | ||
| 3248 | return bool_vector_binop_driver (b, a, b, bool_vector_subsetp); | ||
| 3249 | } | ||
| 3250 | |||
| 3251 | DEFUN ("bool-vector-not", Fbool_vector_not, | ||
| 3252 | Sbool_vector_not, 1, 2, 0, | ||
| 3253 | doc: /* Compute B = ~A. | ||
| 3254 | B must be a bool vector. A must be a bool vector or nil. | ||
| 3255 | If A is nil, allocate a new bool vector in which to store the result. | ||
| 3256 | Return the destination vector. */) | ||
| 3257 | (Lisp_Object a, Lisp_Object b) | ||
| 3258 | { | ||
| 3259 | EMACS_INT nr_bits; | ||
| 3260 | size_t *bdata, *adata; | ||
| 3261 | ptrdiff_t i; | ||
| 3262 | size_t mword; | ||
| 3263 | |||
| 3264 | CHECK_BOOL_VECTOR (a); | ||
| 3265 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3266 | |||
| 3267 | if (NILP (b)) | ||
| 3268 | b = Fmake_bool_vector (make_number (nr_bits), Qnil); | ||
| 3269 | else | ||
| 3270 | { | ||
| 3271 | CHECK_BOOL_VECTOR (b); | ||
| 3272 | nr_bits = min (nr_bits, XBOOL_VECTOR (b)->size); | ||
| 3273 | } | ||
| 3274 | |||
| 3275 | bdata = (size_t*) XBOOL_VECTOR (b)->data; | ||
| 3276 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3277 | i = 0; | ||
| 3278 | |||
| 3279 | eassert_and_assume (nr_bits >= 0); | ||
| 3280 | |||
| 3281 | while (i < nr_bits / BITS_PER_SIZE_T) | ||
| 3282 | { | ||
| 3283 | bdata[i] = ~adata[i]; | ||
| 3284 | i += 1; | ||
| 3285 | } | ||
| 3286 | |||
| 3287 | if (nr_bits % BITS_PER_SIZE_T) | ||
| 3288 | { | ||
| 3289 | mword = size_t_to_host_endian (adata[i]); | ||
| 3290 | mword = ~mword; | ||
| 3291 | mword &= bool_vector_spare_mask (nr_bits); | ||
| 3292 | bdata[i] = size_t_to_host_endian (mword); | ||
| 3293 | } | ||
| 3294 | |||
| 3295 | return b; | ||
| 3296 | } | ||
| 3297 | |||
| 3298 | DEFUN ("bool-vector-count-matches", Fbool_vector_count_matches, | ||
| 3299 | Sbool_vector_count_matches, 2, 2, 0, | ||
| 3300 | doc: /* Count how many elements in A equal B. | ||
| 3301 | A must be a bool vector. B is a generalized bool. */) | ||
| 3302 | (Lisp_Object a, Lisp_Object b) | ||
| 3303 | { | ||
| 3304 | ptrdiff_t count; | ||
| 3305 | EMACS_INT nr_bits; | ||
| 3306 | size_t *adata; | ||
| 3307 | size_t match; | ||
| 3308 | ptrdiff_t i; | ||
| 3309 | |||
| 3310 | CHECK_BOOL_VECTOR (a); | ||
| 3311 | |||
| 3312 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3313 | count = 0; | ||
| 3314 | match = NILP (b) ? (size_t) -1 : 0; | ||
| 3315 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3316 | |||
| 3317 | eassert_and_assume (nr_bits >= 0); | ||
| 3318 | |||
| 3319 | for(i = 0; i < nr_bits / BITS_PER_SIZE_T; ++i) | ||
| 3320 | count += popcount_size_t (adata[i] ^ match); | ||
| 3321 | |||
| 3322 | /* Mask out trailing parts of final mword. */ | ||
| 3323 | if (nr_bits % BITS_PER_SIZE_T) | ||
| 3324 | { | ||
| 3325 | size_t mword = adata[i] ^ match; | ||
| 3326 | mword = size_t_to_host_endian (mword); | ||
| 3327 | count += popcount_size_t (mword & bool_vector_spare_mask (nr_bits)); | ||
| 3328 | } | ||
| 3329 | |||
| 3330 | return make_number (count); | ||
| 3331 | } | ||
| 3332 | |||
| 3333 | DEFUN ("bool-vector-count-matches-at", | ||
| 3334 | Fbool_vector_count_matches_at, | ||
| 3335 | Sbool_vector_count_matches_at, 3, 3, 0, | ||
| 3336 | doc: /* Count how many consecutive elements in A equal B at i. | ||
| 3337 | A must be a bool vector. B is a generalized boolean. i is an | ||
| 3338 | index into the vector.*/) | ||
| 3339 | (Lisp_Object a, Lisp_Object b, Lisp_Object i) | ||
| 3340 | { | ||
| 3341 | ptrdiff_t count; | ||
| 3342 | EMACS_INT nr_bits; | ||
| 3343 | ptrdiff_t offset; | ||
| 3344 | size_t *adata; | ||
| 3345 | size_t twiddle; | ||
| 3346 | size_t mword; /* Machine word. */ | ||
| 3347 | ptrdiff_t pos; | ||
| 3348 | ptrdiff_t nr_words; | ||
| 3349 | |||
| 3350 | CHECK_BOOL_VECTOR (a); | ||
| 3351 | CHECK_NATNUM (i); | ||
| 3352 | |||
| 3353 | nr_bits = XBOOL_VECTOR (a)->size; | ||
| 3354 | if (XFASTINT (i) > nr_bits) /* Allow one past the end for convenience */ | ||
| 3355 | args_out_of_range (a, i); | ||
| 3356 | |||
| 3357 | adata = (size_t*) XBOOL_VECTOR (a)->data; | ||
| 3358 | |||
| 3359 | assume (nr_bits >= 0); | ||
| 3360 | nr_words = ROUNDUP (nr_bits, BITS_PER_SIZE_T) / BITS_PER_SIZE_T; | ||
| 3361 | |||
| 3362 | pos = XFASTINT (i) / BITS_PER_SIZE_T; | ||
| 3363 | offset = XFASTINT (i) % BITS_PER_SIZE_T; | ||
| 3364 | count = 0; | ||
| 3365 | |||
| 3366 | /* By XORing with twiddle, we transform the problem of "count | ||
| 3367 | consecutive equal values" into "count the zero bits". The latter | ||
| 3368 | operation usually has hardware support. */ | ||
| 3369 | twiddle = NILP (b) ? 0 : (size_t) -1; | ||
| 3370 | |||
| 3371 | /* Scan the remainder of the mword at the current offset. */ | ||
| 3372 | if (pos < nr_words && offset != 0) | ||
| 3373 | { | ||
| 3374 | mword = size_t_to_host_endian (adata[pos]); | ||
| 3375 | mword ^= twiddle; | ||
| 3376 | mword >>= offset; | ||
| 3377 | count = count_trailing_zero_bits (mword); | ||
| 3378 | count = min (count, BITS_PER_SIZE_T - offset); | ||
| 3379 | pos += 1; | ||
| 3380 | if (count + offset < BITS_PER_SIZE_T) | ||
| 3381 | return make_number (count); | ||
| 3382 | } | ||
| 3383 | |||
| 3384 | /* Scan whole words until we either reach the end of the vector or | ||
| 3385 | find an mword that doesn't completely match. twiddle is | ||
| 3386 | endian-independent. */ | ||
| 3387 | while (pos < nr_words && adata[pos] == twiddle) | ||
| 3388 | { | ||
| 3389 | count += BITS_PER_SIZE_T; | ||
| 3390 | ++pos; | ||
| 3391 | } | ||
| 3392 | |||
| 3393 | if (pos < nr_words) | ||
| 3394 | { | ||
| 3395 | /* If we stopped because of a mismatch, see how many bits match | ||
| 3396 | in the current mword. */ | ||
| 3397 | mword = size_t_to_host_endian (adata[pos]); | ||
| 3398 | mword ^= twiddle; | ||
| 3399 | count += count_trailing_zero_bits (mword); | ||
| 3400 | } | ||
| 3401 | else if (nr_bits % BITS_PER_SIZE_T != 0) | ||
| 3402 | { | ||
| 3403 | /* If we hit the end, we might have overshot our count. Reduce | ||
| 3404 | the total by the number of spare bits at the end of the | ||
| 3405 | vector. */ | ||
| 3406 | count -= BITS_PER_SIZE_T - nr_bits % BITS_PER_SIZE_T; | ||
| 3407 | } | ||
| 3408 | |||
| 3409 | return make_number (count); | ||
| 3410 | } | ||
| 2959 | 3411 | ||
| 2960 | 3412 | ||
| 2961 | void | 3413 | void |
| @@ -3005,6 +3457,7 @@ syms_of_data (void) | |||
| 3005 | DEFSYM (Qsequencep, "sequencep"); | 3457 | DEFSYM (Qsequencep, "sequencep"); |
| 3006 | DEFSYM (Qbufferp, "bufferp"); | 3458 | DEFSYM (Qbufferp, "bufferp"); |
| 3007 | DEFSYM (Qvectorp, "vectorp"); | 3459 | DEFSYM (Qvectorp, "vectorp"); |
| 3460 | DEFSYM (Qbool_vector_p, "bool-vector-p"); | ||
| 3008 | DEFSYM (Qchar_or_string_p, "char-or-string-p"); | 3461 | DEFSYM (Qchar_or_string_p, "char-or-string-p"); |
| 3009 | DEFSYM (Qmarkerp, "markerp"); | 3462 | DEFSYM (Qmarkerp, "markerp"); |
| 3010 | DEFSYM (Qbuffer_or_string_p, "buffer-or-string-p"); | 3463 | DEFSYM (Qbuffer_or_string_p, "buffer-or-string-p"); |
| @@ -3222,6 +3675,15 @@ syms_of_data (void) | |||
| 3222 | defsubr (&Ssubr_arity); | 3675 | defsubr (&Ssubr_arity); |
| 3223 | defsubr (&Ssubr_name); | 3676 | defsubr (&Ssubr_name); |
| 3224 | 3677 | ||
| 3678 | defsubr (&Sbool_vector_exclusive_or); | ||
| 3679 | defsubr (&Sbool_vector_union); | ||
| 3680 | defsubr (&Sbool_vector_intersection); | ||
| 3681 | defsubr (&Sbool_vector_set_difference); | ||
| 3682 | defsubr (&Sbool_vector_not); | ||
| 3683 | defsubr (&Sbool_vector_subsetp); | ||
| 3684 | defsubr (&Sbool_vector_count_matches); | ||
| 3685 | defsubr (&Sbool_vector_count_matches_at); | ||
| 3686 | |||
| 3225 | set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function); | 3687 | set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->function); |
| 3226 | 3688 | ||
| 3227 | DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, | 3689 | DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum, |