From 9b427b3171b06a83dbcb9ff71c3fff48de791046 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 4 Jul 2022 18:38:57 +0200 Subject: [PATCH] command/*: use std::span instead of ConstBuffer --- src/command/AllCommands.cxx | 14 +++-- src/command/DatabaseCommands.cxx | 25 ++++---- src/command/FileCommands.cxx | 6 +- src/command/MessageCommands.cxx | 7 +-- src/command/OtherCommands.cxx | 2 +- src/command/OutputCommands.cxx | 8 +-- src/command/PlaylistCommands.cxx | 5 +- src/command/QueueCommands.cxx | 11 ++-- src/command/Request.hxx | 98 +++++++++++++++++++++++--------- src/command/StickerCommands.cxx | 16 +++--- src/command/StorageCommands.cxx | 1 - src/command/TagCommands.cxx | 3 +- 12 files changed, 118 insertions(+), 78 deletions(-) diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx index 643a950c1..9e1bf7cfe 100644 --- a/src/command/AllCommands.cxx +++ b/src/command/AllCommands.cxx @@ -337,17 +337,17 @@ command_check_request(const struct command *cmd, Response &r, if (min < 0) return true; - if (min == max && unsigned(max) != args.size) { + if (min == max && unsigned(max) != args.size()) { r.FmtError(ACK_ERROR_ARG, FMT_STRING("wrong number of arguments for \"{}\""), cmd->cmd); return false; - } else if (args.size < unsigned(min)) { + } else if (args.size() < unsigned(min)) { r.FmtError(ACK_ERROR_ARG, FMT_STRING("too few arguments for \"{}\""), cmd->cmd); return false; - } else if (max >= 0 && args.size > unsigned(max)) { + } else if (max >= 0 && args.size() > unsigned(max)) { r.FmtError(ACK_ERROR_ARG, FMT_STRING("too many arguments for \"{}\""), cmd->cmd); @@ -403,13 +403,13 @@ command_process(Client &client, unsigned num, char *line) noexcept } char *argv[COMMAND_ARGV_MAX]; - Request args(argv, 0); try { /* now parse the arguments (quoted or unquoted) */ + std::size_t n_args = 0; while (true) { - if (args.size == COMMAND_ARGV_MAX) { + if (n_args == COMMAND_ARGV_MAX) { r.Error(ACK_ERROR_ARG, "Too many arguments"); return CommandResult::ERROR; } @@ -418,9 +418,11 @@ command_process(Client &client, unsigned num, char *line) noexcept if (a == nullptr) break; - argv[args.size++] = a; + argv[n_args++] = a; } + Request args{argv, n_args}; + /* look up and invoke the command handler */ const struct command *cmd = diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index e1b311022..61a46ba3c 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -30,7 +30,6 @@ #include "client/Client.hxx" #include "client/Response.hxx" #include "tag/ParseName.hxx" -#include "util/ConstBuffer.hxx" #include "util/Exception.hxx" #include "util/StringAPI.hxx" #include "util/ASCII.hxx" @@ -75,8 +74,8 @@ ParseSortTag(const char *s) static unsigned ParseQueuePosition(Request &args, unsigned queue_length) { - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "position")) { - unsigned position = args.ParseUnsigned(args.size - 1, + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "position")) { + unsigned position = args.ParseUnsigned(args.size() - 1, queue_length); args.pop_back(); args.pop_back(); @@ -90,7 +89,7 @@ ParseQueuePosition(Request &args, unsigned queue_length) static unsigned ParseInsertPosition(Request &args, const playlist &playlist) { - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "position")) { + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "position")) { unsigned position = ParseInsertPosition(args.back(), playlist); args.pop_back(); args.pop_back(); @@ -110,8 +109,8 @@ static DatabaseSelection ParseDatabaseSelection(Request args, bool fold_case, SongFilter &filter) { RangeArg window = RangeArg::All(); - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "window")) { - window = args.ParseRange(args.size - 1); + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "window")) { + window = args.ParseRange(args.size() - 1); args.pop_back(); args.pop_back(); @@ -119,7 +118,7 @@ ParseDatabaseSelection(Request args, bool fold_case, SongFilter &filter) TagType sort = TAG_NUM_OF_ITEM_TYPES; bool descending = false; - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "sort")) { + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "sort")) { const char *s = args.back(); if (*s == '-') { descending = true; @@ -236,8 +235,8 @@ CommandResult handle_count(Client &client, Request args, Response &r) { TagType group = TAG_NUM_OF_ITEM_TYPES; - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "group")) { - const char *s = args[args.size - 1]; + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "group")) { + const char *s = args[args.size() - 1]; group = tag_name_parse_i(s); if (group == TAG_NUM_OF_ITEM_TYPES) { r.FmtError(ACK_ERROR_ARG, @@ -317,7 +316,7 @@ handle_list(Client &client, Request args, Response &r) std::unique_ptr filter; std::vector tag_types; - if (args.size == 1 && + if (args.size() == 1 && /* parantheses are the syntax for filter expressions: no compatibility mode */ args.front()[0] != '(') { @@ -333,9 +332,9 @@ handle_list(Client &client, Request args, Response &r) args.shift()); } - while (args.size >= 2 && - StringIsEqual(args[args.size - 2], "group")) { - const char *s = args[args.size - 1]; + while (args.size() >= 2 && + StringIsEqual(args[args.size() - 2], "group")) { + const char *s = args[args.size() - 1]; const auto group = tag_name_parse_i(s); if (group == TAG_NUM_OF_ITEM_TYPES) { r.FmtError(ACK_ERROR_ARG, diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx index bb995b1c3..d04e9644b 100644 --- a/src/command/FileCommands.cxx +++ b/src/command/FileCommands.cxx @@ -138,7 +138,7 @@ public: CommandResult handle_read_comments(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); const char *const uri = args.front(); @@ -288,7 +288,7 @@ read_db_art(Client &client, Response &r, const char *uri, const uint64_t offset) CommandResult handle_album_art(Client &client, Request args, Response &r) { - assert(args.size == 2); + assert(args.size() == 2); const char *uri = args.front(); size_t offset = args.ParseUnsigned(1); @@ -368,7 +368,7 @@ public: CommandResult handle_read_picture(Client &client, Request args, Response &r) { - assert(args.size == 2); + assert(args.size() == 2); const char *const uri = args.front(); const size_t offset = args.ParseUnsigned(1); diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx index 0bbd0e12c..2cfab513e 100644 --- a/src/command/MessageCommands.cxx +++ b/src/command/MessageCommands.cxx @@ -22,7 +22,6 @@ #include "client/Client.hxx" #include "client/List.hxx" #include "client/Response.hxx" -#include "util/ConstBuffer.hxx" #include "Partition.hxx" #include @@ -34,7 +33,7 @@ CommandResult handle_subscribe(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); const char *const channel_name = args[0]; switch (client.Subscribe(channel_name)) { @@ -62,7 +61,7 @@ handle_subscribe(Client &client, Request args, Response &r) CommandResult handle_unsubscribe(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); const char *const channel_name = args[0]; if (client.Unsubscribe(channel_name)) @@ -109,7 +108,7 @@ handle_read_messages(Client &client, CommandResult handle_send_message(Client &client, Request args, Response &r) { - assert(args.size == 2); + assert(args.size() == 2); const char *const channel_name = args[0]; const char *const message_text = args[1]; diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx index 3bf33a9d9..6ed43398d 100644 --- a/src/command/OtherCommands.cxx +++ b/src/command/OtherCommands.cxx @@ -277,7 +277,7 @@ handle_update(Client &client, Request args, Response &r, bool discard) #ifdef ENABLE_DATABASE const char *path = ""; - assert(args.size <= 1); + assert(args.size() <= 1); if (!args.empty()) { path = args.front(); diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx index cb8557f79..d93f32b34 100644 --- a/src/command/OutputCommands.cxx +++ b/src/command/OutputCommands.cxx @@ -30,7 +30,7 @@ CommandResult handle_enableoutput(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); unsigned device = args.ParseUnsigned(0); if (!audio_output_enable_index(client.GetPartition().outputs, device)) { @@ -44,7 +44,7 @@ handle_enableoutput(Client &client, Request args, Response &r) CommandResult handle_disableoutput(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); unsigned device = args.ParseUnsigned(0); if (!audio_output_disable_index(client.GetPartition().outputs, device)) { @@ -58,7 +58,7 @@ handle_disableoutput(Client &client, Request args, Response &r) CommandResult handle_toggleoutput(Client &client, Request args, Response &r) { - assert(args.size == 1); + assert(args.size() == 1); unsigned device = args.ParseUnsigned(0); if (!audio_output_toggle_index(client.GetPartition().outputs, device)) { @@ -90,7 +90,7 @@ IsValidAttributeName(const char *s) noexcept CommandResult handle_outputset(Client &client, Request request, Response &response) { - assert(request.size == 3); + assert(request.size() == 3); const unsigned i = request.ParseUnsigned(0); auto &partition = client.GetPartition(); diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx index af9a75caa..eee002408 100644 --- a/src/command/PlaylistCommands.cxx +++ b/src/command/PlaylistCommands.cxx @@ -41,7 +41,6 @@ #include "Mapper.hxx" #include "fs/AllocatedPath.hxx" #include "time/ChronoUtil.hxx" -#include "util/ConstBuffer.hxx" #include "util/UriExtract.hxx" #include "LocateUri.hxx" @@ -88,7 +87,7 @@ handle_load(Client &client, Request args, [[maybe_unused]] Response &r) auto &playlist = client.GetPlaylist(); const unsigned old_size = playlist.GetLength(); - const unsigned position = args.size > 2 + const unsigned position = args.size() > 2 ? ParseInsertPosition(args[2], partition.playlist) : old_size; @@ -257,7 +256,7 @@ handle_playlistadd(Client &client, Request args, [[maybe_unused]] Response &r) const char *const playlist = args[0]; const char *const uri = args[1]; - if (args.size >= 3) + if (args.size() >= 3) return handle_playlistadd_position(client, playlist, uri, args.ParseUnsigned(2), r); diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx index bc1a06811..4be7c9bed 100644 --- a/src/command/QueueCommands.cxx +++ b/src/command/QueueCommands.cxx @@ -37,7 +37,6 @@ #include "Partition.hxx" #include "Instance.hxx" #include "BulkEdit.hxx" -#include "util/ConstBuffer.hxx" #include "util/Exception.hxx" #include "util/StringAPI.hxx" #include "util/NumberParser.hxx" @@ -82,7 +81,7 @@ handle_add(Client &client, Request args, [[maybe_unused]] Response &r) uri = ""; const auto old_size = partition.playlist.GetLength(); - const unsigned position = args.size > 1 + const unsigned position = args.size() > 1 ? ParseInsertPosition(args[1], partition.playlist) : old_size; @@ -137,7 +136,7 @@ handle_addid(Client &client, Request args, Response &r) const auto queue_length = partition.playlist.queue.GetLength(); - if (args.size > 1) + if (args.size() > 1) to = ParseInsertPosition(args[1], partition.playlist); const SongLoader loader(client); @@ -308,8 +307,8 @@ handle_playlist_match(Client &client, Request args, Response &r, bool fold_case) { RangeArg window = RangeArg::All(); - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "window")) { - window = args.ParseRange(args.size - 1); + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "window")) { + window = args.ParseRange(args.size() - 1); args.pop_back(); args.pop_back(); @@ -317,7 +316,7 @@ handle_playlist_match(Client &client, Request args, Response &r, TagType sort = TAG_NUM_OF_ITEM_TYPES; bool descending = false; - if (args.size >= 2 && StringIsEqual(args[args.size - 2], "sort")) { + if (args.size() >= 2 && StringIsEqual(args[args.size() - 2], "sort")) { const char *s = args.back(); if (*s == '-') { descending = true; diff --git a/src/command/Request.hxx b/src/command/Request.hxx index 7a459bb0f..63b8c5eb5 100644 --- a/src/command/Request.hxx +++ b/src/command/Request.hxx @@ -23,80 +23,124 @@ #include "protocol/ArgParser.hxx" #include "protocol/RangeArg.hxx" #include "Chrono.hxx" -#include "util/ConstBuffer.hxx" #include +#include #include class Response; -class Request : public ConstBuffer { - typedef ConstBuffer Base; +class Request { + std::span args; public: - constexpr Request(const char *const*argv, size_type n) - :Base(argv, n) {} + explicit constexpr Request(const char *const*argv, std::size_t n) + :args(argv, n) {} + + constexpr bool empty() const noexcept { + return args.empty(); + } + + constexpr std::size_t size() const noexcept { + return args.size(); + } + + constexpr const char *front() const noexcept { + return args.front(); + } + + constexpr const char *back() const noexcept { + return args.back(); + } + + constexpr const char *shift() noexcept { + const char *value = args.front(); + args = args.subspan(1); + return value; + } + + constexpr const char *pop_back() noexcept { + const char *value = args.back(); + args = args.first(args.size() - 1); + return value; + } + + constexpr const char *operator[](std::size_t i) const noexcept { + return args[i]; + } + + constexpr auto begin() const noexcept { + return args.begin(); + } + + constexpr auto end() const noexcept { + return args.end(); + } + + constexpr operator std::span() const noexcept { + return args; + } constexpr const char *GetOptional(unsigned idx, const char *default_value=nullptr) const { - return idx < size - ? data[idx] + return idx < size() + ? args[idx] : default_value; } int ParseInt(unsigned idx) const { - assert(idx < size); - return ParseCommandArgInt(data[idx]); + assert(idx < size()); + return ParseCommandArgInt(args[idx]); } int ParseInt(unsigned idx, int min_value, int max_value) const { - assert(idx < size); - return ParseCommandArgInt(data[idx], min_value, max_value); + assert(idx < size()); + return ParseCommandArgInt(args[idx], min_value, max_value); } unsigned ParseUnsigned(unsigned idx) const { - assert(idx < size); - return ParseCommandArgUnsigned(data[idx]); + assert(idx < size()); + return ParseCommandArgUnsigned(args[idx]); } unsigned ParseUnsigned(unsigned idx, unsigned max_value) const { - assert(idx < size); - return ParseCommandArgUnsigned(data[idx], max_value); + assert(idx < size()); + return ParseCommandArgUnsigned(args[idx], max_value); } bool ParseBool(unsigned idx) const { - assert(idx < size); - return ParseCommandArgBool(data[idx]); + assert(idx < size()); + return ParseCommandArgBool(args[idx]); } RangeArg ParseRange(unsigned idx) const { - assert(idx < size); - return ParseCommandArgRange(data[idx]); + assert(idx < size()); + return ParseCommandArgRange(args[idx]); } float ParseFloat(unsigned idx) const { - assert(idx < size); - return ParseCommandArgFloat(data[idx]); + assert(idx < size()); + return ParseCommandArgFloat(args[idx]); } SongTime ParseSongTime(unsigned idx) const { - assert(idx < size); - return ParseCommandArgSongTime(data[idx]); + assert(idx < size()); + return ParseCommandArgSongTime(args[idx]); } SignedSongTime ParseSignedSongTime(unsigned idx) const { - assert(idx < size); - return ParseCommandArgSignedSongTime(data[idx]); + assert(idx < size()); + return ParseCommandArgSignedSongTime(args[idx]); } int ParseOptional(unsigned idx, int default_value) const { - return idx < size + return idx < size() ? ParseInt(idx) : default_value; } RangeArg ParseOptional(unsigned idx, RangeArg default_value) const { - return idx < size + return idx < size() ? ParseRange(idx) : default_value; } diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx index 527ec061e..f04f9d092 100644 --- a/src/command/StickerCommands.cxx +++ b/src/command/StickerCommands.cxx @@ -59,7 +59,7 @@ handle_sticker_song(Response &r, Partition &partition, const char *const cmd = args.front(); /* get song song_id key */ - if (args.size == 4 && StringIsEqual(cmd, "get")) { + if (args.size() == 4 && StringIsEqual(cmd, "get")) { const LightSong *song = db.GetSong(args[2]); assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; @@ -75,7 +75,7 @@ handle_sticker_song(Response &r, Partition &partition, return CommandResult::OK; /* list song song_id */ - } else if (args.size == 3 && StringIsEqual(cmd, "list")) { + } else if (args.size() == 3 && StringIsEqual(cmd, "list")) { const LightSong *song = db.GetSong(args[2]); assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; @@ -85,7 +85,7 @@ handle_sticker_song(Response &r, Partition &partition, return CommandResult::OK; /* set song song_id id key */ - } else if (args.size == 5 && StringIsEqual(cmd, "set")) { + } else if (args.size() == 5 && StringIsEqual(cmd, "set")) { const LightSong *song = db.GetSong(args[2]); assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; @@ -94,13 +94,13 @@ handle_sticker_song(Response &r, Partition &partition, args[3], args[4]); return CommandResult::OK; /* delete song song_id [key] */ - } else if ((args.size == 3 || args.size == 4) && + } else if ((args.size() == 3 || args.size() == 4) && StringIsEqual(cmd, "delete")) { const LightSong *song = db.GetSong(args[2]); assert(song != nullptr); AtScopeExit(&db, song) { db.ReturnSong(song); }; - bool ret = args.size == 3 + bool ret = args.size() == 3 ? sticker_song_delete(sticker_database, *song) : sticker_song_delete_value(sticker_database, *song, args[3]); @@ -111,7 +111,7 @@ handle_sticker_song(Response &r, Partition &partition, return CommandResult::OK; /* find song dir key */ - } else if ((args.size == 4 || args.size == 6) && + } else if ((args.size() == 4 || args.size() == 6) && StringIsEqual(cmd, "find")) { /* "sticker find song a/directory name" */ @@ -120,7 +120,7 @@ handle_sticker_song(Response &r, Partition &partition, StickerOperator op = StickerOperator::EXISTS; const char *value = nullptr; - if (args.size == 6) { + if (args.size() == 6) { /* match the value */ const char *op_s = args[4]; @@ -157,7 +157,7 @@ handle_sticker_song(Response &r, Partition &partition, CommandResult handle_sticker(Client &client, Request args, Response &r) { - assert(args.size >= 3); + assert(args.size() >= 3); auto &instance = client.GetInstance(); if (!instance.HasStickerDatabase()) { diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx index b547a2da6..3def2d6ff 100644 --- a/src/command/StorageCommands.cxx +++ b/src/command/StorageCommands.cxx @@ -22,7 +22,6 @@ #include "Request.hxx" #include "time/ChronoUtil.hxx" #include "util/UriUtil.hxx" -#include "util/ConstBuffer.hxx" #include "fs/Traits.hxx" #include "client/Client.hxx" #include "client/Response.hxx" diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx index 68d7228c2..e473d08e4 100644 --- a/src/command/TagCommands.cxx +++ b/src/command/TagCommands.cxx @@ -23,7 +23,6 @@ #include "client/Response.hxx" #include "tag/ParseName.hxx" #include "queue/Playlist.hxx" -#include "util/ConstBuffer.hxx" #include @@ -52,7 +51,7 @@ handle_cleartagid(Client &client, Request args, Response &r) unsigned song_id = args.ParseUnsigned(0); TagType tag_type = TAG_NUM_OF_ITEM_TYPES; - if (args.size >= 2) { + if (args.size() >= 2) { const char *const tag_name = args[1]; tag_type = tag_name_parse_i(tag_name); if (tag_type == TAG_NUM_OF_ITEM_TYPES) {