He3lixxx
Las funciones de P0553R4: Operaciones con bits están obligados a trabajar solo en enteros sin signo. La propuesta no da una razón para esta restricción. Puedo ver que esto tiene sentido si la representación de bits de un entero con signo no está definida, pero con C++20, tenemos la garantía de que los enteros con signo usan complemento a dos.
Para mí, por lo tanto, parece razonable permitir, por ejemplo, std::popcount
para ser llamado con un tipo entero con signo, ya que una implementación podría simplemente convertir al tipo sin signo correspondiente para realizar la operación de bits en el dominio sin signo.
¿Cuál es la razón por la que P0553R4 agrega esta restricción? (¿Simplemente falta la sincronización entre P0553R4 y P0907R4?)
Bastante simple: las conversiones de ampliación implícitas en tipos sin firmar no cambian el resultado. Las conversiones de ampliación implícitas en tipos firmados (incluidas las promociones) realizan la extensión de signo, lo que cambia el resultado si la entrada fue negativa.
Tener una operación cuyo resultado se vuelve incorrecto debido a la promoción de enteros definitivamente cae en la categoría de “cañón de pie”.
Todavía puede alimentar (patrones de bits que representan) valores negativos a popcount
pero debe tomar el control de la secuencia de conversión, lo que lo ayuda a obtener el resultado que espera.
-
@TedLyngmo: lenguaje-abogado simplemente no es apropiado para un “¿por qué?” pregunta, así que la ignoré. No he ido a buscar en la propuesta, ya que OP indica que ya lo hizo.
– Ben Voigt
5 jun a las 15:20
-
El mismo argumento puede hacerse para
std::countl_zero
con tipos sin firmar– Artyer
5 jun a las 21:14
-
@Artyer: Tener
countl_zero(int)
no ser una sobrecarga válida significa quecountl_zero(x+1)
es un error para estrecho sin firmarx
que promueve a firmadoint
para+
(godbolt.org/z/WGvx644h5), para que te des cuenta de que necesitasstatic_cast<unsigned char>
. Por cierto, incluso con tipos firmados, el conteo de ceros a la izquierda todavía cambia cuando se amplía para enteros no negativos. Además, es el tipo de origen, no el destino, lo que determina si se produce una extensión de cero o de signo, por lo que paraint x
,popcount(x | 1uLL)
ocountl_zero(x | 1uLL)
firmará y extenderá a 64 bits (o lo que sea largo sin firmar).– Peter Cordes
6 de junio a las 4:49
-
@supercat: comúnmente conocido como “log2 ()” Sin una instrucción especial, consulte graphics.stanford.edu/~seander/bithacks.html#IntegerLog
– Ben Voigt
6 de junio a las 22:14
-
@supercat: no estoy diciendo que deba llamar a “log(x)/log(2.0)` para encontrar la posición del bit más alto distinto de cero, estoy diciendo que la función que está proponiendo ya está nombrada — tienes un entero eficiente
log2()
– Ben Voigt
6 jun a las 22:20
ein apoya la huelga de moderadores
popcount
cuenta bits y, por lo tanto, toma un tipo destinado a ser utilizado como un “contenedor de bits”.
- no firmado los tipos enteros están pensados para usarse como contenedores de bits (o valores módulo-2^n).
- firmado los tipos enteros están pensados para usarse como números, algo más abstractos.
Sí, es cierto que desde C++20, la semántica del complemento a dos está garantizada para los enteros con signo, pero ese es un detalle no esencial, que es exactamente el motivo por el cual el complemento a dos no estaba garantizado hasta C++20. Y si no es un abogado de idiomas, es probable que ni siquiera se dé cuenta de este cambio.
Entonces, en lugar de tratar de ser una enciclopedia humana/abogada del lenguaje, haga menos suposiciones sobre la semántica exacta de los tipos que pueden haberse definido de otra manera. Si hace tales suposiciones, es posible que tenga suerte y cuente correctamente; pero es posible que te muerda la respuesta de @BenVoigt.
Véase también la aplicación del mismo principio en mi respuesta a esta pregunta.
/* eslint-disable max-lines-per-function */
import React, { Component } from 'react';
import { withRouter, Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import './UserSearch.css';
import { Grid, TableRow, TableCell, TablePagination } from '@mui/material';
import { Button } from '@material-ui/core';
import MaterialTable from '../../../../components/material/MaterialTable';
import ImpersonateUserButton from '../../../../components/Impersonate/ImpersonateUserButton';
import UserImpersonateModal from '../../../../components/UserImpersonateModal/UserImpersonateModal';
import { impersonateUserApi } from '../../../../api/admin';
import Header from './UserSearchHeader';
import UserSearchButtonContainer from './UserSearchButtonContainer';
import UserSearchCriteria from './UserSearchCriteria';
import {
clearSearchProfileList,
impersonateUserData
} from '../../../../store/admin/actions';
const getTextColor = value => {
switch (value) {
case 'A':
return '#239B06';
case 'P':
return '#CC8007';
default:
return '#EB4D4D ';
}
};
const getStatus = value => {
switch (value) {
case 'A':
return 'Active';
case 'P':
return 'Pending for Approval';
default:
return 'Inactive';
}
};
export class UserSearch extends Component {
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
accountStatus: '',
userID: '',
organizationProfile: '',
submittedOnce: false,
impersonateModalOpen: false,
impersonateUserId: '',
impersonateUserName: '',
impersonateData: {},
controller: {
pageNumber: 0,
rowsPerPage: 5
},
dataLoaded: 0,
searchedUserProfileDefault: {},
formReset: false,
formSubmitted: false
};
this.handlePageChange = this.handlePageChange.bind(this);
this.handleChangeRowsPerPage = this.handleChangeRowsPerPage.bind(this);
}
componentDidMount() {
const { searchedUserProfile, location } = this.props;
this.setState({
formSubmitted: false
});
if (location && location.state && location.state.formSearched === true) {
this.setState({
formReset: true
});
}
this.props.getAdminOrganizationNames();
const impersonateData = localStorage.getItem('impersonateUserData')
? JSON.parse(localStorage.getItem('impersonateUserData'))
: {};
if (
impersonateData &&
impersonateData.isImpersonating != undefined &&
!impersonateData.isImpersonating
) {
this.setState(
{
firstName: impersonateData.firstName,
lastName: impersonateData.lastName,
accountStatus: impersonateData.accountStatus,
organizationProfile: impersonateData.organizationProfile,
userLoginId: this.state.userID
},
() => {
this.searchForProfileHandler(new Event('submit'));
localStorage.removeItem('impersonateUserData');
}
);
}
if (
searchedUserProfile != undefined &&
Object.keys(searchedUserProfile).length > 0 &&
location &&
location.state &&
location.state.formSearched === true
) {
this.setState(
{
firstName: searchedUserProfile.searchUserVO.firstName,
lastName: searchedUserProfile.searchUserVO.lastName,
accountStatus: searchedUserProfile.searchUserVO.accountStatus,
organizationProfile:
searchedUserProfile.searchUserVO.organizationProfile,
userLoginId: this.state.userID
},
() => {
this.searchForProfileHandler(new Event('submit'));
}
);
}
}
handlePageChange = async (event, newPage) => {
const { controller } = this.state;
await this.setState({
controller: {
...controller,
pageNumber: newPage
}
});
this.searchForProfileUpdate();
this.setState({
dataLoaded: 1
});
};
handleChangeRowsPerPage = async event => {
const { controller } = this.state;
await this.setState({
controller: {
...controller,
rowsPerPage: parseInt(event.target.value, 10),
pageNumber: 0
}
});
this.searchForProfileUpdate();
this.setState({
dataLoaded: 1
});
};
userClickedHandler = id => {
this.props.history.push(`/admin/users/edit/${id}`);
};
openImpersonateModal = (key, userName) => e => {
e.preventDefault();
this.setState({
impersonateModalOpen: true,
impersonateUserId: key,
impersonateUserName: userName
});
};
closeImpersonateModal = e => {
e.preventDefault();
this.setState({
impersonateModalOpen: false,
impersonateUserId: '',
impersonateUserName: ''
});
};
impersonateUser = (impersonateUserProfileId, userName) => {
const body = {
doImpersonate: true,
impersonateUserProfileId
};
impersonateUserApi(body)
.then(res => {
if (res) {
const impData = {
isImpersonating: true,
redirectUrl: this.props.location.pathname,
userName: userName,
firstName: this.state.firstName,
lastName: this.state.lastName,
accountStatus: this.state.accountStatus,
organizationProfile: this.state.organizationProfile
};
localStorage.setItem('impersonateUserData', JSON.stringify(impData));
this.props.history.replace("https://stackoverflow.com/");
} else {
this.props.history.replace('/error');
}
})
.catch(err => {
this.props.history.replace('/error');
});
};
searchForProfileUpdate = async () => {
const { controller } = this.state;
const userProfile = {
firstName: this.state.firstName,
lastName: this.state.lastName,
userLoginId: this.state.userID,
accountStatus: this.state.accountStatus,
organizationProfile: this.state.organizationProfile,
organizationProfileId: this.state.organizationProfile.id
};
const pageInfo = {
pageNumber: controller.pageNumber,
rowsPerPage: controller.rowsPerPage
};
this.setState({ formSubmitted: true, submittedOnce: true });
await this.props.getUserProfileSearchResults({
searchUserVO: userProfile,
paginationInfo: pageInfo
});
this.props.getSearchedUserProfile({
searchUserVO: userProfile,
paginationInfo: pageInfo
});
this.setState({ formSubmitted: false });
this.setState({
dataLoaded: 1
});
};
searchForProfileHandler = async e => {
e.preventDefault();
await this.setState({
controller: {
rowsPerPage: 5,
pageNumber: 0
}
});
this.searchForProfileUpdate();
};
clearFieldsHandler = () => {
this.setState({
firstName: '',
lastName: '',
accountStatus: '',
organizationProfile: {},
submittedOnce: false,
formSubmitted: false,
userID: ''
});
this.props.clearSearchProfileList();
this.setState({
controller: {
rowsPerPage: 5,
pageNumber: 0
}
});
this.setState({
dataLoaded: 0
});
this.setState({
formReset: false,
formSubmitted: false
});
};
componentWillUnmount() {
this.setState({
dataLoaded: 0
});
}
updateSearchCriteriaHandler(id, value) {
this.setState({ [id]: value });
this.setState({
controller: {
rowsPerPage: 5,
pageNumber: 0
}
});
}
renderImpersonateButton(user) {
const isEligibleImpersonation =
this.state.impersonateData &&
!this.state.impersonateData.isImpersonating &&
user.internalUserFlag === 'N' &&
user.accountStatus === 'A' &&
user.userLockInd === 'F' &&
!user.loggedInUser &&
Object.keys(this.props.roleMap)[0] !== 'HA';
if (isEligibleImpersonation) {
return (
<Button
variant="outlined"
size="small"
color="secondary"
onClick={this.openImpersonateModal(
user.key,
user.firstName + ' ' + user.lastName
)}
data-test="impersonate-button">
Impersonate
</Button>
);
} else {
return (
<Button
variant="outlined"
size="small"
color="secondary"
disabled
data-test="impersonate-button">
Impersonate
</Button>
);
}
}
render() {
const { userProfiles, userPageInfo } = this.props;
const { controller, dataLoaded, formReset } = this.state;
const tableHeaders = [
'User ID',
'First Name',
'Last Name',
'Email ID',
'Status',
''
];
return (
<Grid container item data-test="user-search-component">
<Grid
container
className="user-search-container"
alignItems="flex-start"
data-test="user-search-criteria-grid"
alignContent="flex-start">
<Header
data-test="user-search-header"
roles={Object.keys(this.props.roleMap)[0]}
/>
<Grid
container
item
className="user-search-criteria-container"
data-test="user-search-criteria-container">
<form
style={{ width: '100%' }}
data-test="user-search-criteria-form"
onSubmit={this.searchForProfileHandler}>
<UserSearchCriteria
adminsOrganizations={this.props.usersOrganizations}
firstName={this.state.firstName}
lastName={this.state.lastName}
userID={this.state.userID}
status={this.state.accountStatus}
businessName={this.state.organizationProfile}
data-test="user-search-criteria"
onSearchCriteriaChange={(elementId, value) =>
this.updateSearchCriteriaHandler(elementId, value)
}
/>
<UserSearchButtonContainer
data-test="user-search-button-container"
clearFields={this.clearFieldsHandler}
userProfile={this.state}
onSubmit={this.searchForProfileHandler}
/>
<UserImpersonateModal
data-test="user-search-impersonate-modal"
isOpen={this.state.impersonateModalOpen}
userProfileId={this.state.impersonateUserId}
userName={this.state.impersonateUserName}
onConfirm={this.impersonateUser}
onCancel={this.closeImpersonateModal}
/>
</form>
</Grid>
{this.state.submittedOnce || formReset ? (
<>
<MaterialTable
data-test="user-search-material-table"
tableHeaders={tableHeaders}
headerAlign={'center'}
count={userPageInfo.totalNumberOfRows}>
{userPageInfo.totalNumberOfRows || dataLoaded === 1
? userProfiles.map(user => (
<TableRow
key={user.key}
style={{ inlineSize: '150px', overflow: 'hidden' }}>
<TableCell align='center' style={{ width: '10%' }}>
<Link
style={{
textDecoration:
user.internalUserFlag === 'Y' ? '' : 'none',
pointerEvents:
user.internalUserFlag === 'Y' ? 'none' : 'auto',
color:
user.internalUserFlag === 'Y'
? 'black'
: '#2477ab'
}}
to={
user.internalUserFlag === 'Y'
? "https://stackoverflow.com/"
: `/admin/users/edit/${user.key}`
}>
{user.userLoginId}
</Link>
</TableCell>
<TableCell
style={{
inlineSize: '150px',
overflow: 'hidden',
width: '20%'
}}
align='center'>
{user.firstName}
</TableCell>
<TableCell
style={{
inlineSize: '150px',
overflow: 'hidden',
width: '20%'
}}
align='center'>
{user.lastName}
</TableCell>
<TableCell
style={{
inlineSize: '150px',
overflow: 'hidden',
width: '20%'
}}
align='center'>
{user.emailId}
</TableCell>
<TableCell
align='center'
style={{
color: getTextColor(user.accountStatus),
width: '15%'
}}>
{getStatus(user.accountStatus)}
</TableCell>
{Object.keys(this.props.roleMap)[0] === 'PA' && (
<TableCell align='center' style={{ width: '15%' }}>
{this.renderImpersonateButton(user)}
</TableCell>
)}
</TableRow>
))
: null}
</MaterialTable>
<span className="user-Table-Pagination">
<TablePagination
component="div"
page={controller.pageNumber}
count={userPageInfo.totalNumberOfRows}
rowsPerPageOptions={[5, 10, 25, 50, 100]}
rowsPerPage={controller.rowsPerPage}
onPageChange={this.handlePageChange}
onRowsPerPageChange={this.handleChangeRowsPerPage}
/>
</span>
</>
) : null}
</Grid>
</Grid>
);
}
}
const mapStateToProps = state => {
return {
usrProfId: state.user.usrProfId,
roleMap: state.user.userRoleMap
};
};
const mapDispatchToProps = {
clearSearchProfileList
};
UserSearch.propTypes = {
getAdminOrganizationNames: PropTypes.func.isRequired,
getUserProfileSearchResults: PropTypes.func.isRequired,
clearSearchProfileList: PropTypes.func.isRequired,
usrProfId: PropTypes.any,
history: PropTypes.object.isRequired,
usersOrganizations: PropTypes.array.isRequired,
userProfiles: PropTypes.array,
searchedUserProfile: PropTypes.object
};
UserSearch.defaultProps = {
userProfiles: [],
usrProfId: ''
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(withRouter(UserSearch));
-
Creo que te has perdido algo…
– 0xNIC
hace 10 horas
-
Probablemente publicaste la respuesta a la pregunta incorrecta y olvidaste el texto de la respuesta.
– Sebastián
hace 5 horas
Al aplicar operaciones bit a bit, como contar el número de bits establecidos (popcount), en enteros con signo, puede haber un comportamiento inesperado debido al bit de signo. Específicamente, el bit de signo puede propagarse durante las operaciones, lo que podría generar resultados incorrectos o un comportamiento indefinido.
– Eldinur
5 de junio a las 14:02
template <typename T> int spopcount(T s) { return popcount(static_cast<std::make_unsigned_t<decltype(s)>>(s)); }
… pero de todos modos, supongo que la propuesta P0553 en sí es anterior a la representación del complemento 2s como propuesta independiente. Algo que se podría “arreglar” fácilmente con una nueva pequeña propuesta. Propuestas como esa necesitan que alguien las proponga.– Eljay
5 de junio a las 14:13
Incluso con la garantía del complemento a dos en C++20, los desbordamientos de enteros con signo todavía tienen UB en C++20. Quizás las razones de la
<bit>
familia de funciones que solo trabajan con tipos sin firmar se puede encontrar en el razonamiento detrás de esa decisión?– Ted Lyngmo
5 de junio a las 14:18
¿Cuál es el caso de uso para contar bits en valores con signo? Todas las recomendaciones para usar máscaras de bits son para usar siempre sin firmar. Y en la extraña posibilidad de que encuentre un caso de uso, puede hacer la conversión usted mismo fácilmente.
– balanza de pagos
5 de junio a las 14:57
@doug “Los tipos enteros con signo han sido compl. de dos desde c++17” – El estándar no requería que los tipos enteros con signo fueran complemento a dos antes de C++20.
– Ted Lyngmo
5 jun a las 15:05