aboutsummaryrefslogtreecommitdiffstats
path: root/src/data.c
diff options
context:
space:
mode:
authorDaniel Colascione2013-09-22 01:31:55 -0800
committerDaniel Colascione2013-09-22 01:31:55 -0800
commit3e0b94e7ff1fc69b077322d672ef5d0b668541c3 (patch)
tree9927abd073960f2460f05a43ae9467cd82c00b9b /src/data.c
parent76880d884d87d0bc674249e292ccda70f31cca0e (diff)
downloademacs-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.c462
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;
54static Lisp_Object Qnatnump; 54static Lisp_Object Qnatnump;
55Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp; 55Lisp_Object Qstringp, Qarrayp, Qsequencep, Qbufferp;
56Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; 56Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp;
57Lisp_Object Qbool_vector_p;
57Lisp_Object Qbuffer_or_string_p; 58Lisp_Object Qbuffer_or_string_p;
58static Lisp_Object Qkeywordp, Qboundp; 59static Lisp_Object Qkeywordp, Qboundp;
59Lisp_Object Qfboundp; 60Lisp_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
2966static inline
2967size_t
2968bool_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
2987static inline
2988unsigned int
2989popcount_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
3002static inline
3003unsigned int
3004popcount_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
3048static inline
3049unsigned int
3050popcount_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
3060static inline
3061unsigned int
3062popcount_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
3073enum 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
3079static inline
3080Lisp_Object
3081bool_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. */
3143static inline
3144unsigned int
3145count_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
3182static inline
3183size_t
3184size_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
3197DEFUN ("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.
3200A, B, and C must be bool vectors. If C is nil, allocate a new bool
3201vector in which to store the result. Return the destination vector if
3202it 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
3209DEFUN ("bool-vector-union", Fbool_vector_union,
3210 Sbool_vector_union, 2, 3, 0,
3211 doc: /* Compute C = A | B, bitwise or.
3212A, B, and C must be bool vectors. If C is nil, allocate a new bool
3213vector in which to store the result. Return the destination vector if
3214it 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
3220DEFUN ("bool-vector-intersection", Fbool_vector_intersection,
3221 Sbool_vector_intersection, 2, 3, 0,
3222 doc: /* Compute C = A & B, bitwise and.
3223A, B, and C must be bool vectors. If C is nil, allocate a new bool
3224vector in which to store the result. Return the destination vector if
3225it 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
3231DEFUN ("bool-vector-set-difference", Fbool_vector_set_difference,
3232 Sbool_vector_set_difference, 2, 3, 0,
3233 doc: /* Compute C = A &~ B, set difference.
3234A, B, and C must be bool vectors. If C is nil, allocate a new bool
3235vector in which to store the result. Return the destination vector if
3236it 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
3242DEFUN ("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
3251DEFUN ("bool-vector-not", Fbool_vector_not,
3252 Sbool_vector_not, 1, 2, 0,
3253 doc: /* Compute B = ~A.
3254B must be a bool vector. A must be a bool vector or nil.
3255If A is nil, allocate a new bool vector in which to store the result.
3256Return 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
3298DEFUN ("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.
3301A 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
3333DEFUN ("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.
3337A must be a bool vector. B is a generalized boolean. i is an
3338index 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
2961void 3413void
@@ -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,