cmdopt: add simple reimplementation of libcmdopt
This commit is contained in:
parent
1d65a7ed77
commit
250b8d21ec
@ -16,6 +16,9 @@ UTIL_FILES = \
|
||||
bezier.hpp \
|
||||
bitwise.cpp \
|
||||
bitwise.hpp \
|
||||
cmdopt.cpp \
|
||||
cmdopt.hpp \
|
||||
cmdopt.ipp \
|
||||
colour.cpp \
|
||||
colour.hpp \
|
||||
colour.ipp \
|
||||
|
263
cmdopt.cpp
Normal file
263
cmdopt.cpp
Normal file
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Licensed 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.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#include "cmdopt.hpp"
|
||||
|
||||
#include "debug.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
|
||||
using util::cmdopt::option::base;
|
||||
using util::cmdopt::option::bytes;
|
||||
using util::cmdopt::option::count;
|
||||
using util::cmdopt::option::value;
|
||||
using util::cmdopt::parser;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
base::base (std::string _name):
|
||||
m_name (_name)
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
base::~base ()
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
base::execute (void)
|
||||
{
|
||||
throw invalid_null (m_name);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
base::execute (const char *restrict)
|
||||
{
|
||||
throw invalid_value (m_name);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
base::start (void)
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void
|
||||
base::finish (void)
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string
|
||||
base::name (void) const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
value<T>::value (std::string _name, T &_data):
|
||||
base (_name),
|
||||
m_data (_data)
|
||||
{ ; }
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
void
|
||||
value<T>::execute (const char *restrict str)
|
||||
{
|
||||
try {
|
||||
std::istringstream os (str);
|
||||
os.exceptions (
|
||||
std::istringstream::failbit
|
||||
| std::istringstream::badbit
|
||||
);
|
||||
os >> m_data;
|
||||
|
||||
if (!os.eof ())
|
||||
throw invalid_value (__func__);
|
||||
} catch (...) {
|
||||
throw invalid_value (__func__);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
T
|
||||
value<T>::data (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
T&
|
||||
value<T>::data (void)
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace util { namespace cmdopt { namespace option {
|
||||
template class value<uint16_t>;
|
||||
template class value<uint32_t>;
|
||||
template class value<uint64_t>;
|
||||
} } }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
void
|
||||
count<T>::execute (void)
|
||||
{
|
||||
++ this->data();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
namespace util { namespace cmdopt { namespace option {
|
||||
template class count<unsigned>;
|
||||
} } }
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
int
|
||||
parser::scan (int argc, char *const *argv)
|
||||
{
|
||||
CHECK_GE (argc, 0);
|
||||
CHECK (argv);
|
||||
|
||||
// start iterating after our program's name
|
||||
int i = 1;
|
||||
while (i < argc) {
|
||||
auto len = strlen (argv[i]);
|
||||
|
||||
// bail if there's no potential for an option
|
||||
if (len < 2 || argv[i][0] != '-')
|
||||
return i;
|
||||
|
||||
// parse longopt
|
||||
auto inc = argv[i][1] == '-'
|
||||
? parse_long (i, argc, argv)
|
||||
: parse_short (i, argc, argv);
|
||||
|
||||
CHECK_GT (inc, 0);
|
||||
i += inc;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
parser::parse_long (int pos, int argc, char *const *argv)
|
||||
{
|
||||
CHECK_LT (pos, argc);
|
||||
CHECK_GE (pos, 0);
|
||||
CHECK_GE (argc, 0);
|
||||
CHECK (argv);
|
||||
|
||||
CHECK_EQ (argv[pos][0], '-');
|
||||
CHECK_EQ (argv[pos][1], '-');
|
||||
|
||||
// break first atom into components and extract the key
|
||||
const char *start = argv[pos] + 2;
|
||||
const char *eq = strchr (start, '=');
|
||||
const char *last = start + strlen (start);
|
||||
|
||||
std::string key { start, eq ? eq : last };
|
||||
|
||||
// find the handler
|
||||
auto handle_pos = std::find_if (m_long.begin (),
|
||||
m_long.end (),
|
||||
[&] (auto i) { return std::get<0> (i) == key; });
|
||||
if (handle_pos == m_long.end ())
|
||||
throw invalid_key (key);
|
||||
|
||||
auto &handler = std::get<1> (*handle_pos);
|
||||
|
||||
// maybe grab a value from the next atom and dispatch
|
||||
if (!eq) {
|
||||
// check the next atom for the value
|
||||
if (pos + 1 < argc)
|
||||
if (argv[pos + 1][0] != '-') {
|
||||
handler.execute (argv[pos+1]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
handler.execute ();
|
||||
} else {
|
||||
handler.execute (eq+1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
int
|
||||
parser::parse_short (int pos, int argc, char *const *argv)
|
||||
{
|
||||
CHECK_LT (pos, argc);
|
||||
CHECK_GE (pos, 0);
|
||||
CHECK_GE (argc, 0);
|
||||
CHECK (argv);
|
||||
|
||||
CHECK_EQ (argv[pos][0], '-');
|
||||
CHECK_NEQ (argv[pos][1], '-');
|
||||
|
||||
// we have a run of no-value keys
|
||||
auto len = strlen (argv[pos]);
|
||||
if (len > 2 || pos + 1 == argc || argv[pos+1][0] == '-') {
|
||||
for (size_t i = 1; i < len; ++i) {
|
||||
auto letter = argv[pos][i];
|
||||
|
||||
auto hpos = std::find_if (m_short.begin (),
|
||||
m_short.end (),
|
||||
[letter] (auto j) { return std::get<0> (j) == letter; });
|
||||
if (hpos == m_short.end ())
|
||||
throw invalid_key (std::to_string (letter));
|
||||
std::get<1> (*hpos).execute ();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// we have a value following
|
||||
auto letter = argv[pos][1];
|
||||
auto hpos = std::find_if (m_short.begin (),
|
||||
m_short.end (),
|
||||
[letter] (auto i) { return std::get<0> (i) == letter; });
|
||||
if (hpos == m_short.end ())
|
||||
throw invalid_key (std::to_string (letter));
|
||||
std::get<1> (*hpos).execute (argv[pos+1]);
|
||||
|
||||
return 2;
|
||||
}
|
117
cmdopt.hpp
Normal file
117
cmdopt.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Licensed 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.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __UTIL_CMDLINE_HPP
|
||||
#define __UTIL_CMDLINE_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace util { namespace cmdopt {
|
||||
namespace option {
|
||||
class base {
|
||||
public:
|
||||
base (std::string name);
|
||||
virtual ~base ();
|
||||
|
||||
virtual void execute (void);
|
||||
virtual void execute (const char *restrict);
|
||||
virtual void start (void);
|
||||
virtual void finish (void);
|
||||
|
||||
std::string name (void) const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class value : public base {
|
||||
public:
|
||||
value (std::string name, T&);
|
||||
|
||||
void execute (const char *restrict) override;
|
||||
|
||||
T data (void) const;
|
||||
T& data (void);
|
||||
|
||||
private:
|
||||
T& m_data;
|
||||
};
|
||||
|
||||
|
||||
template <typename T = unsigned>
|
||||
class count : public value<T> {
|
||||
public:
|
||||
count (std::string name);
|
||||
void execute (void) override;
|
||||
};
|
||||
|
||||
|
||||
class bytes : public value<size_t> {
|
||||
public:
|
||||
bytes (std::string name);
|
||||
void execute (const char *restrict) override;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class error : public std::runtime_error
|
||||
{ using runtime_error::runtime_error; };
|
||||
|
||||
class invalid_key : public error
|
||||
{ using error::error; };
|
||||
|
||||
class invalid_value : public error
|
||||
{ using error::error; };
|
||||
|
||||
class invalid_null : public error
|
||||
{ using error::error; };
|
||||
|
||||
|
||||
class parser {
|
||||
public:
|
||||
template <typename T, typename ...Args>
|
||||
T& add (char shortname,
|
||||
std::string longname,
|
||||
std::string description,
|
||||
Args&&...);
|
||||
|
||||
int scan (int argc, char *const *argv);
|
||||
|
||||
private:
|
||||
int parse_long (int pos, int argc, char *const *argv);
|
||||
int parse_short (int pos, int argc, char *const *argv);
|
||||
|
||||
|
||||
using short_t = std::tuple<char,option::base&>;
|
||||
using long_t = std::tuple<std::string,option::base&>;
|
||||
|
||||
std::vector<short_t> m_short;
|
||||
std::vector<long_t> m_long;
|
||||
|
||||
std::vector<std::unique_ptr<option::base>> m_options;
|
||||
};
|
||||
} }
|
||||
|
||||
#include "cmdopt.ipp"
|
||||
|
||||
#endif
|
37
cmdopt.ipp
Normal file
37
cmdopt.ipp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Licensed 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.
|
||||
*
|
||||
* Copyright 2013 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifdef __UTIL_CMDLINE_IPP
|
||||
#error
|
||||
#endif
|
||||
#define __UTIL_CMDLINE_IPP
|
||||
|
||||
namespace util { namespace cmdopt {
|
||||
template <typename T, typename ...Args>
|
||||
T&
|
||||
parser::add (char shortname, std::string longname, std::string description, Args&&... args)
|
||||
{
|
||||
auto handler = std::make_unique<T> (longname, std::forward<Args> (args)...);
|
||||
T& ref = *handler;
|
||||
|
||||
m_short.emplace_back (shortname, ref);
|
||||
m_long .emplace_back (longname, ref);
|
||||
|
||||
m_options.emplace_back (std::move (handler));
|
||||
|
||||
return ref;
|
||||
}
|
||||
} }
|
@ -270,20 +270,33 @@ adjust_ocean (util::image::buffer<float> &height,
|
||||
static const unsigned THERMAL_ITERATIONS = 10;
|
||||
static const unsigned HYDRAULIC_ITERATIONS = 100;
|
||||
|
||||
#include "cmdopt.hpp"
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
// setup the output buffer
|
||||
// setup default variables
|
||||
#ifdef ENABLE_DEBUGGING
|
||||
util::extent2u size {320, 240};
|
||||
util::extent2u res {320, 240};
|
||||
#else
|
||||
util::extent2u size {1920, 1080};
|
||||
util::extent2u res {1920, 1080};
|
||||
#endif
|
||||
util::image::buffer<float> img (size);
|
||||
|
||||
uint64_t seed = time (nullptr);
|
||||
|
||||
// fill variables from arguments
|
||||
util::cmdopt::parser args;
|
||||
args.add<util::cmdopt::option::value<size_t>> ('w', "width", "output image width", res.w);
|
||||
args.add<util::cmdopt::option::value<size_t>> ('h', "height", "output image height", res.h);
|
||||
args.add<util::cmdopt::option::value<uint64_t>> ('s', "seed", "random seed", seed);
|
||||
//args.add<util::cmdopt::option::value<unsigned>> ('o', "octaves", "total fractal iterations", octaves);
|
||||
//args.add<util::cmdopt::option::value<float>> ('H', "hurst", "Hurst exponent", H);
|
||||
|
||||
args.scan (argc, argv);
|
||||
|
||||
util::image::buffer<float> img (res);
|
||||
|
||||
// setup the noise generator
|
||||
#if 0
|
||||
//util::noise::fractal::fbm<float, util::noise::basis::worley<float>> b (seed);
|
||||
@ -294,7 +307,7 @@ main (void)
|
||||
util::noise::fractal::hetero<float, util::noise::basis::value<float,util::lerp::quintic>> b (seed);
|
||||
|
||||
b.octaves (8);
|
||||
b.frequency (10.f / size.w);
|
||||
b.frequency (10.f / res.w);
|
||||
b.lacunarity = 2.f;
|
||||
b.H = 1.0f;
|
||||
b.seed (seed);
|
||||
@ -306,21 +319,21 @@ main (void)
|
||||
util::noise::fractal::fbm<float, util::noise::basis::perlin<float,util::lerp::quintic>>
|
||||
> b (seed, { 0.13f, 0.13f });
|
||||
|
||||
b.data.frequency (1.f / size.w);
|
||||
b.data.frequency (1.f / res.w);
|
||||
b.perturb[0].octaves (4);
|
||||
b.perturb[1].octaves (4);
|
||||
b.perturb[0].frequency (10.f / size.w);
|
||||
b.perturb[1].frequency (10.f / size.w);
|
||||
b.perturb[0].frequency (10.f / res.w);
|
||||
b.perturb[1].frequency (10.f / res.w);
|
||||
#endif
|
||||
|
||||
// generate the values. offset positions slightly to observe simple axis issues with perlin basis
|
||||
{
|
||||
auto offset = util::vector2f { -100 };
|
||||
|
||||
for (size_t y = 0; y < size.h; ++y)
|
||||
for (size_t x = 0; x < size.w; ++x) {
|
||||
for (size_t y = 0; y < res.h; ++y)
|
||||
for (size_t x = 0; x < res.w; ++x) {
|
||||
auto v = b (util::point2f {float (x), float (y)} + offset);
|
||||
img.data ()[y * size.w + x] = v;
|
||||
img.data ()[y * res.w + x] = v;
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,7 +355,7 @@ main (void)
|
||||
|
||||
std::cerr << "thermal_erosion\n";
|
||||
for (size_t i = 0; i < THERMAL_ITERATIONS; ++i)
|
||||
thermal_erode (soft, to_radians (30.f), 1.f / size.w, 0.f);
|
||||
thermal_erode (soft, to_radians (30.f), 1.f / res.w, 0.f);
|
||||
|
||||
hydraulic_erode (soft, HYDRAULIC_ITERATIONS);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user