(size_t) & ((struct element *) 0) -> member

本文介绍了一种计算C/C++中结构体成员相对于结构体起始位置偏移的方法。通过将0地址转换为指向结构体的指针并获取成员地址的方式,在编译阶段即可确定成员的偏移量。

(size_t) & ((struct element *) 0) -> member

求出member在element中的相对位置。

计算结构体成员偏移的。
相当于把0地址转换为指向element结构的指针,然后取其成员地址,自然就是该结构体成员的偏移量。
该语句看似访问0地址,实际只是在编译阶段执行的,并不会引起异常

csdn

/**************************************************************************** * drivers/sensors/sensor.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include <nuttx/config.h> #include <sys/types.h> #include <stdbool.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <errno.h> #include <debug.h> #include <poll.h> #include <fcntl.h> #include <nuttx/list.h> #include <nuttx/kmalloc.h> #include <nuttx/circbuf.h> #include <nuttx/mutex.h> #include <nuttx/sensors/sensor.h> #include <nuttx/lib/lib.h> /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Device naming ************************************************************/ #define ROUND_DOWN(x, y) (((x) / (y)) * (y)) #define DEVNAME_FMT "/dev/uorb/sensor_%s%s%d" #define DEVNAME_UNCAL "_uncal" #define TIMING_BUF_ESIZE (sizeof(uint32_t)) /**************************************************************************** * Private Types ****************************************************************************/ struct sensor_axis_map_s { int8_t src_x; int8_t src_y; int8_t src_z; int8_t sign_x; int8_t sign_y; int8_t sign_z; }; /* This structure describes sensor meta */ struct sensor_meta_s { size_t esize; FAR char *name; }; typedef enum sensor_role_e { SENSOR_ROLE_NONE, SENSOR_ROLE_WR, SENSOR_ROLE_RD, SENSOR_ROLE_RDWR, } sensor_role_t; /* This structure describes user info of sensor, the user may be * advertiser or subscriber */ struct sensor_user_s { /* The common info */ struct list_node node; /* Node of users list */ struct pollfd *fds; /* The poll structure of thread waiting events */ sensor_role_t role; /* The is used to indicate user's role based on open flags */ bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ /* The subscriber info * Support multi advertisers to subscribe their own data when they * appear in dual role */ struct sensor_ustate_s state; }; /* This structure describes the state of the upper half driver */ struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */ struct sensor_state_s state; /* The state of sensor device */ struct circbuf_s timing; /* The circular buffer of generation */ struct circbuf_s buffer; /* The circular buffer of data */ rmutex_t lock; /* Manages exclusive access to file operations */ struct list_node userlist; /* List of users */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role); static int sensor_open(FAR struct file *filep); static int sensor_close(FAR struct file *filep); static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); /**************************************************************************** * Private Data ****************************************************************************/ static const struct sensor_axis_map_s g_remap_tbl[] = { { 0, 1, 2, 1, 1, 1 }, /* P0 */ { 1, 0, 2, 1, -1, 1 }, /* P1 */ { 0, 1, 2, -1, -1, 1 }, /* P2 */ { 1, 0, 2, -1, 1, 1 }, /* P3 */ { 0, 1, 2, -1, 1, -1 }, /* P4 */ { 1, 0, 2, -1, -1, -1 }, /* P5 */ { 0, 1, 2, 1, -1, -1 }, /* P6 */ { 1, 0, 2, 1, 1, -1 }, /* P7 */ }; static const struct sensor_meta_s g_sensor_meta[] = { {0, NULL}, {sizeof(struct sensor_accel), "accel"}, {sizeof(struct sensor_mag), "mag"}, {sizeof(struct sensor_orientation), "orientation"}, {sizeof(struct sensor_gyro), "gyro"}, {sizeof(struct sensor_light), "light"}, {sizeof(struct sensor_baro), "baro"}, {sizeof(struct sensor_noise), "noise"}, {sizeof(struct sensor_prox), "prox"}, {sizeof(struct sensor_rgb), "rgb"}, {sizeof(struct sensor_accel), "linear_accel"}, {sizeof(struct sensor_rotation), "rotation"}, {sizeof(struct sensor_humi), "humi"}, {sizeof(struct sensor_temp), "temp"}, {sizeof(struct sensor_pm25), "pm25"}, {sizeof(struct sensor_pm1p0), "pm1p0"}, {sizeof(struct sensor_pm10), "pm10"}, {sizeof(struct sensor_event), "motion_detect"}, {sizeof(struct sensor_event), "step_detector"}, {sizeof(struct sensor_step_counter), "step_counter"}, {sizeof(struct sensor_ph), "ph"}, {sizeof(struct sensor_hrate), "hrate"}, {sizeof(struct sensor_event), "tilt_detector"}, {sizeof(struct sensor_event), "wake_gesture"}, {sizeof(struct sensor_event), "glance_gesture"}, {sizeof(struct sensor_event), "pickup_gesture"}, {sizeof(struct sensor_event), "wrist_tilt"}, {sizeof(struct sensor_orientation), "device_orientation"}, {sizeof(struct sensor_pose_6dof), "pose_6dof"}, {sizeof(struct sensor_gas), "gas"}, {sizeof(struct sensor_event), "significant_motion"}, {sizeof(struct sensor_hbeat), "hbeat"}, {sizeof(struct sensor_force), "force"}, {sizeof(struct sensor_hall), "hall"}, {sizeof(struct sensor_event), "offbody_detector"}, {sizeof(struct sensor_uv), "uv"}, {sizeof(struct sensor_angle), "hinge_angle"}, {sizeof(struct sensor_ir), "ir"}, {sizeof(struct sensor_hcho), "hcho"}, {sizeof(struct sensor_tvoc), "tvoc"}, {sizeof(struct sensor_dust), "dust"}, {sizeof(struct sensor_ecg), "ecg"}, {sizeof(struct sensor_ppgd), "ppgd"}, {sizeof(struct sensor_ppgq), "ppgq"}, {sizeof(struct sensor_impd), "impd"}, {sizeof(struct sensor_ots), "ots"}, {sizeof(struct sensor_co2), "co2"}, {sizeof(struct sensor_cap), "cap"}, {sizeof(struct sensor_eng), "eng"}, {sizeof(struct sensor_gnss), "gnss"}, {sizeof(struct sensor_gnss_satellite), "gnss_satellite"}, {sizeof(struct sensor_gnss_measurement), "gnss_measurement"}, {sizeof(struct sensor_gnss_clock), "gnss_clock"}, {sizeof(struct sensor_gnss_geofence_event), "gnss_geofence_event"}, }; static const struct file_operations g_sensor_fops = { sensor_open, /* open */ sensor_close, /* close */ sensor_read, /* read */ sensor_write, /* write */ NULL, /* seek */ sensor_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ sensor_poll /* poll */ }; /**************************************************************************** * Private Functions ****************************************************************************/ static void sensor_lock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_lock(&upper->lock); } static void sensor_unlock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_unlock(&upper->lock); } static int sensor_update_interval(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t interval) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_interval = interval; uint32_t min_latency = interval != UINT32_MAX ? user->state.latency : UINT32_MAX; int ret = 0; if (interval == user->state.interval) { return 0; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_interval > tmp->state.interval) { min_interval = tmp->state.interval; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } if (lower->ops->set_interval) { if (min_interval != UINT32_MAX && min_interval != upper->state.min_interval) { uint32_t expected_interval = min_interval; ret = lower->ops->set_interval(lower, filep, &min_interval); if (ret < 0) { return ret; } else if (min_interval > expected_interval) { return -EINVAL; } } if (min_latency == UINT32_MAX) { min_latency = 0; } if (lower->ops->batch && (min_latency != upper->state.min_latency || (min_interval != upper->state.min_interval && min_latency))) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret >= 0) { upper->state.min_latency = min_latency; } } } upper->state.min_interval = min_interval; user->state.interval = interval; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static int sensor_update_latency(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t latency) { FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *tmp; uint32_t min_latency = latency; int ret = 0; if (latency == user->state.latency) { return 0; } if (user->state.interval == UINT32_MAX) { user->state.latency = latency; return 0; } if (latency <= upper->state.min_latency) { goto update; } list_for_every_entry(&upper->userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp->state.interval == UINT32_MAX) { continue; } if (min_latency > tmp->state.latency) { min_latency = tmp->state.latency; } } update: if (min_latency == UINT32_MAX) { min_latency = 0; } if (min_latency == upper->state.min_latency) { user->state.latency = latency; return ret; } if (lower->ops->batch) { ret = lower->ops->batch(lower, filep, &min_latency); if (ret < 0) { return ret; } } upper->state.min_latency = min_latency; user->state.latency = latency; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper, unsigned long nums) { uint32_t interval = upper->state.min_interval != UINT32_MAX ? upper->state.min_interval : 1; while (nums-- > 0) { upper->state.generation += interval; circbuf_overwrite(&upper->timing, &upper->state.generation, TIMING_BUF_ESIZE); } } static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { long delta = (long long)upper->state.generation - user->state.generation; if (delta <= 0) { return false; } else if (user->state.interval == UINT32_MAX) { return true; } else { /* Check whether next generation user want in buffer. * generation next generation(not published yet) * ____v_____________v * ////|//////^ | * ^ middle point * next generation user want */ return delta >= user->state.interval - (upper->state.min_interval >> 1); } } static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { uint32_t generation; long delta; circbuf_peek(&upper->timing, &generation, TIMING_BUF_ESIZE); delta = (long long)generation - user->state.generation; if (delta > 0) { user->bufferpos = upper->timing.tail / TIMING_BUF_ESIZE; if (user->state.interval == UINT32_MAX) { user->state.generation = generation - 1; } else { delta -= upper->state.min_interval >> 1; user->state.generation += ROUND_DOWN(delta, user->state.interval); } } } static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, FAR char *buffer, size_t len) { uint32_t generation; ssize_t ret = 0; size_t nums; size_t pos; size_t end; sensor_catch_up(upper, user); nums = upper->timing.head / TIMING_BUF_ESIZE - user->bufferpos; if (len < nums * upper->state.esize) { nums = len / upper->state.esize; } len = nums * upper->state.esize; /* Take samples continuously */ if (user->state.interval == UINT32_MAX) { if (buffer != NULL) { ret = circbuf_peekat(&upper->buffer, user->bufferpos * upper->state.esize, buffer, len); } else { ret = len; } user->bufferpos += nums; circbuf_peekat(&upper->timing, (user->bufferpos - 1) * TIMING_BUF_ESIZE, &user->state.generation, TIMING_BUF_ESIZE); return ret; } /* Take samples one-bye-one, to determine whether a sample needed: * * If user's next generation is on the left side of middle point, * we should copy this sample for user. * next_generation(or end) * ________________v____ * timing buffer: //|//////. | * ^ middle * generation * next sample(or end) * ________________v____ * data buffer: | | * ^ * sample */ pos = user->bufferpos; end = upper->timing.head / TIMING_BUF_ESIZE; circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &generation, TIMING_BUF_ESIZE); while (pos++ != end) { uint32_t next_generation; long delta; if (pos * TIMING_BUF_ESIZE == upper->timing.head) { next_generation = upper->state.generation + upper->state.min_interval; } else { circbuf_peekat(&upper->timing, pos * TIMING_BUF_ESIZE, &next_generation, TIMING_BUF_ESIZE); } delta = next_generation + generation - ((user->state.generation + user->state.interval) << 1); if (delta >= 0) { if (buffer != NULL) { ret += circbuf_peekat(&upper->buffer, (pos - 1) * upper->state.esize, buffer + ret, upper->state.esize); } else { ret += upper->state.esize; } user->bufferpos = pos; user->state.generation += user->state.interval; if (ret >= len) { break; } } generation = next_generation; } if (pos - 1 == end && sensor_is_updated(upper, user)) { generation = upper->state.generation - user->state.generation + (upper->state.min_interval >> 1); user->state.generation += ROUND_DOWN(generation, user->state.interval); } return ret; } static void sensor_pollnotify_one(FAR struct sensor_user_s *user, pollevent_t eventset, sensor_role_t role) { if (!(user->role & role)) { return; } if (eventset == POLLPRI) { user->changed = true; } poll_notify(&user->fds, 1, eventset); } static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role) { FAR struct sensor_user_s *user; list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { sensor_pollnotify_one(user, eventset, role); } } static int sensor_open(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; int ret = 0; nxrmutex_lock(&upper->lock); user = kmm_zalloc(sizeof(struct sensor_user_s)); if (user == NULL) { ret = -ENOMEM; goto errout_with_lock; } if (lower->ops->open) { ret = lower->ops->open(lower, filep); if (ret < 0) { goto errout_with_user; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { if (upper->state.nsubscribers == 0 && lower->ops->activate) { ret = lower->ops->activate(lower, filep, true); if (ret < 0) { goto errout_with_open; } } user->role |= SENSOR_ROLE_RD; upper->state.nsubscribers++; } if (filep->f_oflags & O_WROK) { user->role |= SENSOR_ROLE_WR; upper->state.nadvertisers++; if (filep->f_oflags & SENSOR_PERSIST) { lower->persist = true; } } } if (upper->state.generation && lower->persist) { user->state.generation = upper->state.generation - 1; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE - 1; } else { user->state.generation = upper->state.generation; user->bufferpos = upper->timing.head / TIMING_BUF_ESIZE; } user->state.interval = UINT32_MAX; user->state.esize = upper->state.esize; nxsem_init(&user->buffersem, 0, 0); list_add_tail(&upper->userlist, &user->node); /* The new user generation, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); filep->f_priv = user; goto errout_with_lock; errout_with_open: if (lower->ops->close) { lower->ops->close(lower, filep); } errout_with_user: kmm_free(user); errout_with_lock: nxrmutex_unlock(&upper->lock); return ret; } static int sensor_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; int ret = 0; nxrmutex_lock(&upper->lock); if (lower->ops->close) { ret = lower->ops->close(lower, filep); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } } if ((filep->f_oflags & O_DIRECT) == 0) { if (filep->f_oflags & O_RDOK) { upper->state.nsubscribers--; if (upper->state.nsubscribers == 0 && lower->ops->activate) { lower->ops->activate(lower, filep, false); } } if (filep->f_oflags & O_WROK) { upper->state.nadvertisers--; } } list_delete(&user->node); sensor_update_latency(filep, upper, user, UINT32_MAX); sensor_update_interval(filep, upper, user, UINT32_MAX); nxsem_destroy(&user->buffersem); /* The user is closed, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); nxrmutex_unlock(&upper->lock); kmm_free(user); return ret; } static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; ssize_t ret; if (!len) { return -EINVAL; } nxrmutex_lock(&upper->lock); if (lower->ops->fetch) { if (buffer == NULL) { return -EINVAL; } if (!(filep->f_oflags & O_NONBLOCK)) { nxrmutex_unlock(&upper->lock); ret = nxsem_wait_uninterruptible(&user->buffersem); if (ret < 0) { return ret; } nxrmutex_lock(&upper->lock); } else if (!upper->state.nsubscribers) { ret = -EAGAIN; goto out; } ret = lower->ops->fetch(lower, filep, buffer, len); } else if (circbuf_is_empty(&upper->buffer)) { ret = -ENODATA; } else if (sensor_is_updated(upper, user)) { ret = sensor_do_samples(upper, user, buffer, len); } else if (lower->persist) { if (buffer == NULL) { ret = upper->state.esize; } else { /* Persistent device can get latest old data if not updated. */ ret = circbuf_peekat(&upper->buffer, (user->bufferpos - 1) * upper->state.esize, buffer, upper->state.esize); } } else { ret = -ENODATA; } out: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; return lower->push_event(lower->priv, buffer, buflen); } static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; uint32_t arg1 = (uint32_t)arg; int ret = 0; switch (cmd) { case SNIOC_GET_STATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &upper->state, sizeof(upper->state)); user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_USTATE: { nxrmutex_lock(&upper->lock); memcpy((FAR void *)(uintptr_t)arg, &user->state, sizeof(user->state)); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_INTERVAL: { nxrmutex_lock(&upper->lock); ret = sensor_update_interval(filep, upper, user, arg1 ? arg1 : UINT32_MAX); nxrmutex_unlock(&upper->lock); } break; case SNIOC_BATCH: { nxrmutex_lock(&upper->lock); ret = sensor_update_latency(filep, upper, user, arg1); nxrmutex_unlock(&upper->lock); } break; case SNIOC_SELFTEST: { if (lower->ops->selftest == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->selftest(lower, filep, arg); } break; case SNIOC_SET_CALIBVALUE: { if (lower->ops->set_calibvalue == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->set_calibvalue(lower, filep, arg); } break; case SNIOC_CALIBRATE: { if (lower->ops->calibrate == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->calibrate(lower, filep, arg); } break; case SNIOC_SET_USERPRIV: { nxrmutex_lock(&upper->lock); upper->state.priv = (uint64_t)arg; nxrmutex_unlock(&upper->lock); } break; case SNIOC_SET_BUFFER_NUMBER: { nxrmutex_lock(&upper->lock); if (!circbuf_is_init(&upper->buffer)) { if (arg1 >= lower->nbuffer) { lower->nbuffer = arg1; upper->state.nbuffer = arg1; } else { ret = -ERANGE; } } else { ret = -EBUSY; } nxrmutex_unlock(&upper->lock); } break; case SNIOC_UPDATED: { nxrmutex_lock(&upper->lock); *(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user); nxrmutex_unlock(&upper->lock); } break; case SNIOC_GET_INFO: { if (lower->ops->get_info == NULL) { ret = -ENOTSUP; break; } ret = lower->ops->get_info(lower, filep, (FAR struct sensor_device_info_s *)(uintptr_t)arg); } break; case SNIOC_GET_EVENTS: { nxrmutex_lock(&upper->lock); *(FAR unsigned int *)(uintptr_t)arg = user->event; user->event = 0; user->changed = false; nxrmutex_unlock(&upper->lock); } break; case SNIOC_FLUSH: { nxrmutex_lock(&upper->lock); /* If the sensor is not activated, return -EINVAL. */ if (upper->state.nsubscribers == 0) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (lower->ops->flush != NULL) { /* Lower half driver will do flush in asynchronous mode, * flush will be completed until push event happened with * bytes is zero. */ ret = lower->ops->flush(lower, filep); if (ret >= 0) { user->flushing = true; } } else { /* If flush is not supported, complete immediately */ user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } nxrmutex_unlock(&upper->lock); } break; default: /* Lowerhalf driver process other cmd. */ if (lower->ops->control) { ret = lower->ops->control(lower, filep, cmd, arg); } else { ret = -ENOTTY; } break; } return ret; } static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode = filep->f_inode; FAR struct sensor_upperhalf_s *upper = inode->i_private; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user = filep->f_priv; pollevent_t eventset = 0; int semcount; int ret = 0; nxrmutex_lock(&upper->lock); if (setup) { /* Don't have enough space to store fds */ if (user->fds) { ret = -ENOSPC; goto errout; } user->fds = fds; fds->priv = filep; if (lower->ops->fetch) { /* Always return POLLIN for fetch data directly(non-block) */ if (filep->f_oflags & O_NONBLOCK) { eventset |= POLLIN; } else { nxsem_get_value(&user->buffersem, &semcount); if (semcount > 0) { eventset |= POLLIN; } } } else if (sensor_is_updated(upper, user)) { eventset |= POLLIN; } if (user->changed) { eventset |= POLLPRI; } poll_notify(&fds, 1, eventset); } else { user->fds = NULL; fds->priv = NULL; } errout: nxrmutex_unlock(&upper->lock); return ret; } static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_lowerhalf_s *lower = upper->lower; FAR struct sensor_user_s *user; unsigned long envcount; int semcount; int ret; nxrmutex_lock(&upper->lock); if (bytes == 0) { list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (user->flushing) { user->flushing = false; user->event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user->role); } } nxrmutex_unlock(&upper->lock); return 0; } envcount = bytes / upper->state.esize; if (bytes != envcount * upper->state.esize) { nxrmutex_unlock(&upper->lock); return -EINVAL; } if (!circbuf_is_init(&upper->buffer)) { /* Initialize sensor buffer when data is first generated */ ret = circbuf_init(&upper->buffer, NULL, lower->nbuffer * upper->state.esize); if (ret < 0) { nxrmutex_unlock(&upper->lock); return ret; } ret = circbuf_init(&upper->timing, NULL, lower->nbuffer * TIMING_BUF_ESIZE); if (ret < 0) { circbuf_uninit(&upper->buffer); nxrmutex_unlock(&upper->lock); return ret; } } circbuf_overwrite(&upper->buffer, data, bytes); sensor_generate_timing(upper, envcount); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { if (sensor_is_updated(upper, user)) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } } nxrmutex_unlock(&upper->lock); return bytes; } static void sensor_notify_event(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_user_s *user; int semcount; nxrmutex_lock(&upper->lock); list_for_every_entry(&upper->userlist, user, struct sensor_user_s, node) { nxsem_get_value(&user->buffersem, &semcount); if (semcount < 1) { nxsem_post(&user->buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } nxrmutex_unlock(&upper->lock); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sensor_remap_vector_raw16 * * Description: * This function remap the sensor data according to the place position on * board. The value of place is determined base on g_remap_tbl. * * Input Parameters: * in - A pointer to input data need remap. * out - A pointer to output data. * place - The place position of sensor on board, * ex:SENSOR_BODY_COORDINATE_PX * ****************************************************************************/ void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out, int place) { FAR const struct sensor_axis_map_s *remap; int16_t tmp[3]; DEBUGASSERT(place < (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0]))); remap = &g_remap_tbl[place]; tmp[0] = in[remap->src_x] * remap->sign_x; tmp[1] = in[remap->src_y] * remap->sign_y; tmp[2] = in[remap->src_z] * remap->sign_z; memcpy(out, tmp, sizeof(tmp)); } /**************************************************************************** * Name: sensor_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * We will register the chararter device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by * numbers. eg: accel0, accel1 * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. If the * devno alerady exists, -EEXIST will be returned. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; int ret; DEBUGASSERT(lower != NULL); path = lib_get_pathbuffer(); if (path == NULL) { return -ENOMEM; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); ret = sensor_custom_register(lower, path, g_sensor_meta[lower->type].esize); lib_put_pathbuffer(path); return ret; } /**************************************************************************** * Name: sensor_custom_register * * Description: * This function binds an instance of a "lower half" Sensor driver with the * "upper half" Sensor device and registers that device so that can be used * by application code. * * You can register the character device type by specific path and esize. * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device. ex: /dev/uorb/xxx. * esize - The element size of intermediate circular buffer. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, FAR const char *path, size_t esize) { FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); if (lower->type >= SENSOR_TYPE_COUNT || !esize) { snerr("ERROR: type is invalid\n"); return ret; } /* Allocate the upper-half data structure */ upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s)); if (!upper) { snerr("ERROR: Allocation failed\n"); return -ENOMEM; } /* Initialize the upper-half data structure */ list_initialize(&upper->userlist); upper->state.esize = esize; upper->state.min_interval = UINT32_MAX; if (lower->ops->activate) { upper->state.nadvertisers = 1; } nxrmutex_init(&upper->lock); /* Bind the lower half data structure member */ lower->priv = upper; lower->sensor_lock = sensor_lock; lower->sensor_unlock = sensor_unlock; if (!lower->ops->fetch) { if (!lower->nbuffer) { lower->nbuffer = 1; } lower->push_event = sensor_push_event; } else { lower->notify_event = sensor_notify_event; lower->nbuffer = 0; } #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); if (lower == NULL) { ret = -EIO; goto rpmsg_err; } #endif upper->state.nbuffer = lower->nbuffer; upper->lower = lower; sninfo("Registering %s\n", path); ret = register_driver(path, &g_sensor_fops, 0666, upper); if (ret) { goto drv_err; } return ret; drv_err: #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); rpmsg_err: #endif nxrmutex_destroy(&upper->lock); kmm_free(upper); return ret; } /**************************************************************************** * Name: sensor_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; path = lib_get_pathbuffer(); if (path == NULL) { return; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower->type].name, lower->uncalibrated ? DEVNAME_UNCAL : "", devno); sensor_custom_unregister(lower, path); lib_put_pathbuffer(path); } /**************************************************************************** * Name: sensor_custom_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. This API corresponds to the sensor_custom_register. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device, ex: /dev/uorb/xxx ****************************************************************************/ void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, FAR const char *path) { FAR struct sensor_upperhalf_s *upper; DEBUGASSERT(lower != NULL); DEBUGASSERT(lower->priv != NULL); upper = lower->priv; sninfo("UnRegistering %s\n", path); unregister_driver(path); #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); #endif nxrmutex_destroy(&upper->lock); if (circbuf_is_init(&upper->buffer)) { circbuf_uninit(&upper->buffer); circbuf_uninit(&upper->timing); } kmm_free(upper); }
07-11
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "list.h" /** * @brief 这个是内核链表的一个demo * 1. 第一自己需要的数据类型 ,其中必须包含一个 struct list_head 的变量 2. 定义头节点,并初始化 3. 增加结点,malloc自己的结构体,填入自己需要的数据 调用list_add ,把当前结点加入链表 4. 遍历所有元素list_for_each_entry_safe, */ typedef struct { int id; char name[50]; struct list_head node; } PER; int add_per(struct list_head *head, int id, char *name) { PER *per = malloc(sizeof(PER)); if (NULL == per) { perror("add_per malloc error\n"); return 1; } per->id = id; strcpy(per->name, name); //头插 // list_add(&per->node, head); list_add_tail(&per->node, head); return 0; } int show(struct list_head *head) { // 遍历所有数据, // pos 当前要访问的PER结构体指针 ,n是pos的下一个指针 , // head 链表的头结点 // member 在自定义的结构体中 结点的变量名 // list_for_each_entry_safe(pos, n, head, member) for PER *tmp; PER *next; list_for_each_entry_safe(tmp, next, head, node) { printf("%d %s\n", tmp->id, tmp->name); } return 0; } /** * @brief * * @param head * @param id 需要删除数据的编号 * @return int */ PER* find_per(struct list_head *head, char *name) { PER *tmp; list_for_each_entry(tmp, head, node) { if (strcmp(tmp->name, name) == 0) { printf("找到节点:id=%d, name=%s\n", tmp->id, tmp->name); return tmp; } } printf("未找到姓名为「%s」的节点\n", name); return NULL; } int modify_per(struct list_head *head, char *old_name, int new_id, char *new_name) { PER *target = find_per(head, old_name); if (target == NULL) { return 1; } target->id = new_id; if (strlen(new_name) >= sizeof(target->name)) { printf("无效名字"); return 2; } strcpy(target->name, new_name); printf("修改成功:原姓名「%s」→ 新id=%d, 新姓名「%s」\n", old_name, new_id, new_name); return 0; } int del_per(struct list_head *head, int id) { PER *tmp; PER *next; list_for_each_entry_safe(tmp, next, head, node) { if (tmp->id == id) { list_del(&tmp->node); free(tmp); } } return 0; } int main(int argc, char **argv) { //头结点,不包含有效数据,head->next 是链表中第一个有效数据 struct list_head head; //双向循环链表, 当前结点的prev,next 都指向自己 INIT_LIST_HEAD(&head); add_per(&head, 1, "zhagnsan"); add_per(&head, 2, "lisi"); add_per(&head, 3, "wangmazi"); add_per(&head, 4, "guanerge"); add_per(&head, 5, "liubei "); show(&head); del_per(&head, 1); printf("------------del--------------\n"); show(&head); find_per(&head, "lisi"); // system("pause"); return 0; } #ifndef _LINUX_LIST_H #define _LINUX_LIST_H #include <linux/stddef.h> #include <stdio.h> //#include <linux/poison.h> //#include <linux/prefetch.h> //#include <asm/system.h> /* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */ // #define LIST_POISON1 ((void *) 0x00100100) // #define LIST_POISON2 ((void *) 0x00200200) #define LIST_POISON1 ((void *) 0) #define LIST_POISON2 ((void *) 0) #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );}) struct list_head { struct list_head *next, *prev; }; #define LIST_HEAD_INIT(name) \ { \ &(name), &(name) \ } #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT (name) static inline void INIT_LIST_HEAD (struct list_head *list) { list->next = list; list->prev = list; } /* * Insert a new entry between two known consecutive entries. * * This is only for internal list manipulation where we know * the prev/next entries already! */ #ifndef CONFIG_DEBUG_LIST static inline void __list_add (struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } #else extern void __list_add (struct list_head *new, struct list_head *prev, struct list_head *next); #endif /** * list_add - add a new entry * @new: new entry to be added * @head: list head to add it after * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void list_add (struct list_head *new, struct list_head *head) { __list_add (new, head, head->next); } /** * list_add_tail - add a new entry * @new: new entry to be added * @head: list head to add it before * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void list_add_tail (struct list_head *new, struct list_head *head) { __list_add (new, head->prev, head); } /* * Delete a list entry by making the prev/next entries * point to each other. * * This is only for internal list manipulation where we know * the prev/next entries already! */ static inline void __list_del (struct list_head *prev, struct list_head *next) { next->prev = prev; prev->next = next; } /** * list_del - deletes entry from list. * @entry: the element to delete from the list. * Note: list_empty() on entry does not return true after this, the entry is * in an undefined state. */ #ifndef CONFIG_DEBUG_LIST static inline void list_del (struct list_head *entry) { __list_del (entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } #else extern void list_del (struct list_head *entry); #endif /** * list_replace - replace old entry by new one * @old : the element to be replaced * @new : the new element to insert * * If @old was empty, it will be overwritten. */ static inline void list_replace (struct list_head *old, struct list_head *new) { new->next = old->next; new->next->prev = new; new->prev = old->prev; new->prev->next = new; } static inline void list_replace_init (struct list_head *old, struct list_head *new) { list_replace (old, new); INIT_LIST_HEAD (old); } /** * list_del_init - deletes entry from list and reinitialize it. * @entry: the element to delete from the list. */ static inline void list_del_init (struct list_head *entry) { __list_del (entry->prev, entry->next); INIT_LIST_HEAD (entry); } /** * list_move - delete from one list and add as another's head * @list: the entry to move * @head: the head that will precede our entry */ static inline void list_move (struct list_head *list, struct list_head *head) { __list_del (list->prev, list->next); list_add (list, head); } /** * list_move_tail - delete from one list and add as another's tail * @list: the entry to move * @head: the head that will follow our entry */ static inline void list_move_tail (struct list_head *list, struct list_head *head) { __list_del (list->prev, list->next); list_add_tail (list, head); } /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test * @head: the head of the list */ static inline int list_is_last (const struct list_head *list, const struct list_head *head) { return list->next == head; } /** * list_empty - tests whether a list is empty * @head: the list to test. */ static inline int list_empty (const struct list_head *head) { return head->next == head; } /** * list_empty_careful - tests whether a list is empty and not being modified * @head: the list to test * * Description: * tests whether a list is empty _and_ checks that no other CPU might be * in the process of modifying either member (next or prev) * * NOTE: using list_empty_careful() without synchronization * can only be safe if the only activity that can happen * to the list entry is list_del_init(). Eg. it cannot be used * if another CPU could re-list_add() it. */ static inline int list_empty_careful (const struct list_head *head) { struct list_head *next = head->next; return (next == head) && (next == head->prev); } /** * list_is_singular - tests whether a list has just one entry. * @head: the list to test. */ static inline int list_is_singular (const struct list_head *head) { return !list_empty (head) && (head->next == head->prev); } static inline void __list_cut_position (struct list_head *list, struct list_head *head, struct list_head *entry) { struct list_head *new_first = entry->next; list->next = head->next; list->next->prev = list; list->prev = entry; entry->next = list; head->next = new_first; new_first->prev = head; } /** * list_cut_position - cut a list into two * @list: a new list to add all removed entries * @head: a list with entries * @entry: an entry within head, could be the head itself * and if so we won't cut the list * * This helper moves the initial part of @head, up to and * including @entry, from @head to @list. You should * pass on @entry an element you know is on @head. @list * should be an empty list or a list you do not care about * losing its data. * */ static inline void list_cut_position (struct list_head *list, struct list_head *head, struct list_head *entry) { if (list_empty (head)) return; if (list_is_singular (head) && (head->next != entry && head != entry)) return; if (entry == head) INIT_LIST_HEAD (list); else __list_cut_position (list, head, entry); } static inline void __list_splice (const struct list_head *list, struct list_head *prev, struct list_head *next) { struct list_head *first = list->next; struct list_head *last = list->prev; first->prev = prev; prev->next = first; last->next = next; next->prev = last; } /** * list_splice - join two lists, this is designed for stacks * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice (const struct list_head *list, struct list_head *head) { if (!list_empty (list)) __list_splice (list, head, head->next); } /** * list_splice_tail - join two lists, each list being a queue * @list: the new list to add. * @head: the place to add it in the first list. */ static inline void list_splice_tail (struct list_head *list, struct list_head *head) { if (!list_empty (list)) __list_splice (list, head->prev, head); } /** * list_splice_init - join two lists and reinitialise the emptied list. * @list: the new list to add. * @head: the place to add it in the first list. * * The list at @list is reinitialised */ static inline void list_splice_init (struct list_head *list, struct list_head *head) { if (!list_empty (list)) { __list_splice (list, head, head->next); INIT_LIST_HEAD (list); } } /** * list_splice_tail_init - join two lists and reinitialise the emptied list * @list: the new list to add. * @head: the place to add it in the first list. * * Each of the lists is a queue. * The list at @list is reinitialised */ static inline void list_splice_tail_init (struct list_head *list, struct list_head *head) { if (!list_empty (list)) { __list_splice (list, head->prev, head); INIT_LIST_HEAD (list); } } /** * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) container_of (ptr, type, member) /** * list_first_entry - get the first element from a list * @ptr: the list head to take the element from. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. * * Note, that list is expected to be not empty. */ #define list_first_entry(ptr, type, member) \ list_entry ((ptr)->next, type, member) /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) \ for (pos = (head)->next; prefetch (pos->next), pos != (head); \ pos = pos->next) /** * __list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. * * This variant differs from list_for_each() in that it's the * simplest possible list iteration code, no prefetching is done. * Use this for code that knows the list to be very short (empty * or 1 entry) most of the time. */ #define __list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next) /** * list_for_each_prev - iterate over a list backwards * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each_prev(pos, head) \ for (pos = (head)->prev; prefetch (pos->prev), pos != (head); \ pos = pos->prev) /** * list_for_each_safe - iterate over a list safe against removal of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_safe(pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \ pos = n, n = pos->next) /** * list_for_each_prev_safe - iterate over a list backwards safe against removal * of list entry * @pos: the &struct list_head to use as a loop cursor. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. */ #define list_for_each_prev_safe(pos, n, head) \ for (pos = (head)->prev, n = pos->prev; \ prefetch (pos->prev), pos != (head); pos = n, n = pos->prev) /** * list_for_each_entry - iterate over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry(pos, head, member) \ for (pos = list_entry ((head)->next, typeof(*pos), member); \ prefetch (pos->member.next), &pos->member != (head); \ pos = list_entry (pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_reverse(pos, head, member) \ for (pos = list_entry ((head)->prev, typeof(*pos), member); \ prefetch (pos->member.prev), &pos->member != (head); \ pos = list_entry (pos->member.prev, typeof(*pos), member)) /** * list_prepare_entry - prepare a pos entry for use in * list_for_each_entry_continue() * @pos: the type * to use as a start point * @head: the head of the list * @member: the name of the list_struct within the struct. * * Prepares a pos entry for use as a start point in * list_for_each_entry_continue(). */ #define list_prepare_entry(pos, head, member) \ ((pos) ?: list_entry (head, typeof(*pos), member)) /** * list_for_each_entry_continue - continue iteration over list of given type * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Continue to iterate over list of given type, continuing after * the current position. */ #define list_for_each_entry_continue(pos, head, member) \ for (pos = list_entry (pos->member.next, typeof(*pos), member); \ prefetch (pos->member.next), &pos->member != (head); \ pos = list_entry (pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_continue_reverse - iterate backwards from the given * point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Start to iterate over list of given type backwards, continuing after * the current position. */ #define list_for_each_entry_continue_reverse(pos, head, member) \ for (pos = list_entry (pos->member.prev, typeof(*pos), member); \ prefetch (pos->member.prev), &pos->member != (head); \ pos = list_entry (pos->member.prev, typeof(*pos), member)) /** * list_for_each_entry_from - iterate over list of given type from the current * point * @pos: the type * to use as a loop cursor. * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing from current position. */ #define list_for_each_entry_from(pos, head, member) \ for (; prefetch (pos->member.next), &pos->member != (head); \ pos = list_entry (pos->member.next, typeof(*pos), member)) /** * list_for_each_entry_safe - iterate over list of given type safe against * removal of list entry * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. */ #define list_for_each_entry_safe(pos, n, head, member) \ for (pos = list_entry ((head)->next, typeof(*pos), member), \ n = list_entry (pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry (n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_continue * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ #define list_for_each_entry_safe_continue(pos, n, head, member) \ for (pos = list_entry (pos->member.next, typeof(*pos), member), \ n = list_entry (pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry (n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_from * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate over list of given type from current point, safe against * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ for (n = list_entry (pos->member.next, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry (n->member.next, typeof(*n), member)) /** * list_for_each_entry_safe_reverse * @pos: the type * to use as a loop cursor. * @n: another type * to use as temporary storage * @head: the head for your list. * @member: the name of the list_struct within the struct. * * Iterate backwards over list of given type, safe against removal * of list entry. */ #define list_for_each_entry_safe_reverse(pos, n, head, member) \ for (pos = list_entry ((head)->prev, typeof(*pos), member), \ n = list_entry (pos->member.prev, typeof(*pos), member); \ &pos->member != (head); \ pos = n, n = list_entry (n->member.prev, typeof(*n), member)) /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is * too wasteful. * You lose the ability to access the tail in O(1). */ struct hlist_head { struct hlist_node *first; }; struct hlist_node { struct hlist_node *next, **pprev; }; #define HLIST_HEAD_INIT \ { \ .first = NULL \ } #define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } #define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) static inline void INIT_HLIST_NODE (struct hlist_node *h) { h->next = NULL; h->pprev = NULL; } static inline int hlist_unhashed (const struct hlist_node *h) { return !h->pprev; } static inline int hlist_empty (const struct hlist_head *h) { return !h->first; } static inline void __hlist_del (struct hlist_node *n) { struct hlist_node *next = n->next; struct hlist_node **pprev = n->pprev; *pprev = next; if (next) next->pprev = pprev; } static inline void hlist_del (struct hlist_node *n) { __hlist_del (n); n->next = LIST_POISON1; n->pprev = LIST_POISON2; } static inline void hlist_del_init (struct hlist_node *n) { if (!hlist_unhashed (n)) { __hlist_del (n); INIT_HLIST_NODE (n); } } static inline void hlist_add_head (struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; h->first = n; n->pprev = &h->first; } /* next must be != NULL */ static inline void hlist_add_before (struct hlist_node *n, struct hlist_node *next) { n->pprev = next->pprev; n->next = next; next->pprev = &n->next; *(n->pprev) = n; } static inline void hlist_add_after (struct hlist_node *n, struct hlist_node *next) { next->next = n->next; n->next = next; next->pprev = &n->next; if (next->next) next->next->pprev = &next->next; } /* * Move a list from one list head to another. Fixup the pprev * reference of the first entry if it exists. */ static inline void hlist_move_list (struct hlist_head *old, struct hlist_head *new) { new->first = old->first; if (new->first) new->first->pprev = &new->first; old->first = NULL; } #define hlist_entry(ptr, type, member) container_of (ptr, type, member) #define hlist_for_each(pos, head) \ for (pos = (head)->first; pos && ({ \ prefetch (pos->next); \ 1; \ }); \ pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; pos && ({ \ n = pos->next; \ 1; \ }); \ pos = n) /** * hlist_for_each_entry - iterate over list of given type * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry(tpos, pos, head, member) \ for (pos = (head)->first; \ pos && ({ \ prefetch (pos->next); \ 1; \ }) \ && ({ \ tpos = hlist_entry (pos, typeof(*tpos), member); \ 1; \ }); \ pos = pos->next) /** * hlist_for_each_entry_continue - iterate over a hlist continuing after * current point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_continue(tpos, pos, member) \ for (pos = (pos)->next; \ pos && ({ \ prefetch (pos->next); \ 1; \ }) \ && ({ \ tpos = hlist_entry (pos, typeof(*tpos), member); \ 1; \ }); \ pos = pos->next) /** * hlist_for_each_entry_from - iterate over a hlist continuing from current * point * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_from(tpos, pos, member) \ for (; pos && ({ \ prefetch (pos->next); \ 1; \ }) \ && ({ \ tpos = hlist_entry (pos, typeof(*tpos), member); \ 1; \ }); \ pos = pos->next) /** * hlist_for_each_entry_safe - iterate over list of given type safe against * removal of list entry * @tpos: the type * to use as a loop cursor. * @pos: the &struct hlist_node to use as a loop cursor. * @n: another &struct hlist_node to use as temporary storage * @head: the head for your list. * @member: the name of the hlist_node within the struct. */ #define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ for (pos = (head)->first; \ pos && ({ \ n = pos->next; \ 1; \ }) \ && ({ \ tpos = hlist_entry (pos, typeof(*tpos), member); \ 1; \ }); \ pos = n) #endif 错误信息为In file included from main.c:4:0: main.c: In function ‘find_per’: list.h:417:8: warning: implicit declaration of function ‘prefetch’; did you mean ‘rpmatch’? [-Wimplicit-function-declaration] prefetch (pos->member.next), &pos->member != (head); \ ^ main.c:63:5: note: in expansion of macro ‘list_for_each_entry’ list_for_each_entry(tmp, head, node) ^~~~~~~~~~~~~~~~~~~ /tmp/cce8BVSj.o: In function `find_per': main.c:(.text+0x297): undefined reference to `prefetch' collect2: error: ld returned 1 exit status,该如何修改
最新发布
08-24
/** * implement a container like std::map */ #ifndef SJTU_MAP_HPP #define SJTU_MAP_HPP #include <cstdio> // only for std::less<T> #include <functional> #include <cstddef> #include "utility.hpp" #include "exceptions.hpp" namespace sjtu { template< class Key, class T, class Compare = std::less <Key> > class AAtree{ public: typedef pair<const Key, T> value_type; struct Node { Node *lson, *rson, *parent; int level; value_type data; Node(const value_type &d, int lv = 1, Node *p = nullptr, Node *l = nullptr, Node *r = nullptr) : data(d), level(lv), parent(p), lson(l), rson(r) {} ~Node() { data.~value_type(); } }; Node *root; size_t tree_size; Compare comp; AAtree(): root(nullptr), tree_size(0) {} AAtree(const AAtree &other) { root = copyTree(other.root, nullptr); tree_size = other.tree_size; } AAtree &operator=(const AAtree &other) { if (this != &other) { clear(root); root = copyTree(other.root, nullptr); tree_size = other.tree_size; } return *this; } ~AAtree() { clear(root); tree_size = 0; } Node *skew(Node *node) { if (!node || !node->lson) return node; if (node->lson->level == node->level) { Node *L = node->lson; node->lson = L->rson; if (L->rson) L->rson->parent = node; L->rson = node; L->parent = node->parent; node->parent = L; return L; } return node; } Node *split(Node *node) { if (!node || !node->rson || !node->rson->rson) return node; if (node->level == node->rson->rson->level) { Node *R = node->rson; node->rson = R->lson; if (R->lson) R->lson->parent = node; R->lson = node; R->parent = node->parent; node->parent = R; ++R->level; return R; } return node; } Node *insert(Node *node, const value_type &value, Node *parent = nullptr) { if (!node) { ++tree_size; return new Node(value, 1, parent); } if (comp(value.first, node->data.first)) { node->lson = insert(node->lson, value, node); node->lson->parent = node; } else if (comp(node->data.first, value.first)) { node->rson = insert(node->rson, value, node); node->rson->parent = node; } else return node; node = skew(node); node = split(node); return node; } // 删除节点时正确处理父子关系 // void erase(Node*& node, const Key& key) { // if (!node) return; // if (comp(key, node->data.first)) { // erase(node->lson, key); // } else if (comp(node->data.first, key)) { // erase(node->rson, key); // } else { // if (node->lson && node->rson) { // // 处理有两个子节点的情况 // Node* successor = findMin(node->rson); // Node *newNode = new Node(successor->data, node->level, node->parent, node->lson, node->rson); // if (newNode->lson) newNode->lson->parent = newNode; // if (newNode->rson) newNode->rson->parent = newNode; // if (newNode->parent) { // if (newNode->parent->lson == node) { // newNode->parent->lson = newNode; // } else { // newNode->parent->rson = newNode; // } // } // erase(newNode->rson, successor->data.first); // 递归删除后继节点 // delete node; // node = newNode; // } else { // Node* temp = node; // node = (node->lson) ? node->lson : node->rson; // delete temp; // 释放内存后,node指针已被上层更新 // } // } // // 删除后重新平衡 // if (node) { // node = skew(node); // node = split(node); // } // } Node *erase(Node *node, const Key &key) { if (!node) return nullptr; if (comp(key, node->data.first)) { node->lson = erase(node->lson, key); if (node->lson) node->lson->parent = node; } else if (comp(node->data.first, key)) { node->rson = erase(node->rson, key); if (node->rson) node->rson->parent = node; } else { if (!node->lson && !node->rson) { if (node->parent) { if (node->parent->lson == node) { node->parent->lson = nullptr; } else { node->parent->rson = nullptr; } } delete node; node = nullptr; --tree_size; return nullptr; } else if (!node->lson) { Node *temp = node->rson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } else if (!node->rson) { Node *temp = node->lson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } Node *predecessor = node->lson; while (predecessor->rson) predecessor = predecessor->rson; Node *newNode = new Node(predecessor->data, node->level, node->parent, node->lson, node->rson); if (newNode->lson) newNode->lson->parent = newNode; if (newNode->rson) newNode->rson->parent = newNode; if (newNode->parent) { if (newNode->parent->lson == node) { newNode->parent->lson = newNode; } else { newNode->parent->rson = newNode; } } newNode->lson = erase(newNode->lson, predecessor->data.first); if (newNode->lson) newNode->lson->parent = newNode; delete node; node = newNode; } if (node->lson && node->rson) { size_t min_level = node->lson->level < node->rson->level ? node->lson->level : node->rson->level; if (node->level > min_level + 1) { node->level = min_level + 1; if (node->rson && node->rson->level > node->level) node->rson->level = node->level; } } node = skew(node); node->rson = skew(node->rson); if (node->rson) node->rson->rson = skew(node->rson->rson); node = split(node); node->rson = split(node->rson); return node; } Node *find(Node *node, const Key &key) const { while (node) { if (comp(key, node->data.first)) node = node->lson; else if (comp(node->data.first, key)) node = node->rson; else return node; } return nullptr; } Node *findMin(Node *node) const { if (!node) return nullptr; // printf("In findmin: %d\n", (node)); while (node->lson) node = node->lson; // printf("finish find min\n"); return node; } Node *findMax(Node *node) const { if (!node) return nullptr; while (node->rson) node = node->rson; return node; } Node *successor(Node *node) const { // printf("in successor\n"); if (!node) return nullptr; // printf("in successor2\n"); if (node->rson) return findMin(node->rson); // printf("in successor3\n"); Node *parent = node->parent; while (parent && node == parent->rson) { node = parent; parent = parent->parent; } // printf("finish successor\n"); return parent; } Node *predecessor(Node *node) const { if (!node) return nullptr; if (node->lson) return findMax(node->lson); Node *parent = node->parent; while (parent && node == parent->lson) { node = parent; parent = parent->parent; } return parent; } Node *copyTree(Node *node, Node *parent) { if (!node) return nullptr; Node *newNode = new Node(node->data, node->level, parent); newNode->lson = copyTree(node->lson, newNode); newNode->rson = copyTree(node->rson, newNode); return newNode; } void clear(Node *node) { if (!node) return; clear(node->lson); clear(node->rson); delete node; node = nullptr; } }; template< class Key, class T, class Compare = std::less <Key> > class map { public: /** * the internal type of data. * it should have a default constructor, a copy constructor. * You can use sjtu::map as value_type by typedef. */ typedef pair<const Key, T> value_type; AAtree<Key, T, Compare> aa_tree; /** * see BidirectionalIterator at CppReference for help. * * if there is anything wrong throw invalid_iterator. * like it = map.begin(); --it; * or it = map.end(); ++end(); */ typedef typename AAtree<Key, T, Compare>::Node Node; class const_iterator; class iterator { private: /** * TODO add data members * just add whatever you want. */ map* container; Node *node; public: iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } iterator(const iterator &other):container(other.container), node(other.node) { // TODO } /** * TODO iter++ */ iterator operator++(int) { if (!node) throw invalid_iterator(); iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ iterator operator--(int) { iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.node && container == rhs.container; } bool operator==(const const_iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.node || container != rhs.container; } bool operator!=(const const_iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; class const_iterator { // it should has similar member method as iterator. // and it should be able to construct from an iterator. private: // data members. map* container; Node *node; public: // const_iterator(const map *c = nullptr, Node *n = nullptr): container(const_cast<map*>(c)), node(n) { // // TODO // } const_iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } const_iterator(const const_iterator &other): container(other.container), node(other.node) { // TODO } const_iterator(const iterator &other) { // TODO container = other.getContainer(); node = other.getNode(); } /** * TODO iter++ */ const_iterator operator++(int) { if (!node) throw invalid_iterator(); const_iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ const_iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ const_iterator operator--(int) { const_iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ const_iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ const value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } bool operator==(const const_iterator &rhs) const { return node == rhs.node && container == rhs.container; } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } bool operator!=(const const_iterator &rhs) const { return node != rhs.node || container != rhs.container; } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ const value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; /** * TODO two constructors */ map(): aa_tree() {} map(const map &other): aa_tree(other.aa_tree) {} /** * TODO assignment operator */ map &operator=(const map &other) { if (this != &other) { aa_tree = other.aa_tree; } return *this; } /** * TODO Destructors */ ~map() {} /** * TODO * access specified element with bounds checking * Returns a reference to the mapped value of the element with key equivalent to key. * If no such element exists, an exception of type `index_out_of_bound' */ T &at(const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } const T &at(const Key &key) const { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } /** * TODO * access specified element * Returns a reference to the value that is mapped to a key equivalent to key, * performing an insertion if such key does not already exist. */ T &operator[](const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (node) return node->data.second; aa_tree.root = aa_tree.insert(aa_tree.root, value_type(key, T())); return aa_tree.find(aa_tree.root, key)->data.second; } /** * behave like at() throw index_out_of_bound if such key does not exist. */ const T &operator[](const Key &key) const { return at(key); } /** * return a iterator to the beginning */ iterator begin() { return iterator(this, aa_tree.findMin(aa_tree.root)); } const_iterator cbegin() const { return const_iterator(const_cast<map*>(this), aa_tree.findMin(aa_tree.root)); } /** * return a iterator to the end * in fact, it returns past-the-end. */ iterator end() { return iterator(this, nullptr); } const_iterator cend() const { return const_iterator(const_cast<map*>(this), nullptr); } /** * checks whether the container is empty * return true if empty, otherwise false. */ bool empty() const { return aa_tree.tree_size == 0; } /** * returns the number of elements. */ size_t size() const { return aa_tree.tree_size; } /** * clears the contents */ void clear() { aa_tree.clear(aa_tree.root); aa_tree.root = nullptr; aa_tree.tree_size = 0; } /** * insert an element. * return a pair, the first of the pair is * the iterator to the new element (or the element that prevented the insertion), * the second one is true if insert successfully, or false. */ pair<iterator, bool> insert(const value_type &value) { auto node = aa_tree.find(aa_tree.root, value.first); if (node) return {iterator(this, node), false}; aa_tree.root = aa_tree.insert(aa_tree.root, value); node = aa_tree.find(aa_tree.root, value.first); return {iterator(this, node), true}; } /** * erase the element at pos. * * throw if pos pointed to a bad element (pos == this->end() || pos points an element out of this) */ void erase(iterator pos) { if (pos == end() || pos.getContainer() != this) throw invalid_iterator(); aa_tree.root = aa_tree.erase(aa_tree.root, (*pos).first); } /** * Returns the number of elements with key * that compares equivalent to the specified argument, * which is either 1 or 0 * since this container does not allow duplicates. * The default method of check the equivalence is !(a < b || b > a) */ size_t count(const Key &key) const { return aa_tree.find(aa_tree.root, key) ? 1 : 0; } /** * Finds an element with key equivalent to key. * key value of the element to search for. * Iterator to an element with key equivalent to key. * If no such element is found, past-the-end (see end()) iterator is returned. */ iterator find(const Key &key) { return iterator(this, aa_tree.find(aa_tree.root, key)); } const_iterator find(const Key &key) const { return const_iterator(const_cast<map*>(this), aa_tree.find(aa_tree.root, key)); } }; } #endif 这段代码,Q.erase(it--)会失效,为什么?
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值