refactor and add benchmark