Compare commits
40 commits
Author | SHA1 | Date | |
---|---|---|---|
|
daa2dfc077 | ||
|
69af73e315 | ||
|
2769a3a0ad | ||
|
1dae994364 | ||
|
6130bdee66 | ||
|
8abebb692a | ||
|
4bb3629a76 | ||
|
cc34c03648 | ||
|
c5e034c3ac | ||
|
686fd07e08 | ||
|
abec11b35b | ||
|
42f69296f6 | ||
|
d4970c8d76 | ||
|
57d5f34ee5 | ||
|
1c88d49452 | ||
|
7a62bebf76 | ||
|
70170ea995 | ||
|
d10300509e | ||
|
7dd7f5610b | ||
|
94d807fc67 | ||
|
8c8930f5c5 | ||
|
fe00d47e02 | ||
|
c6eb4cb6ae | ||
|
5b669caddb | ||
|
b843fc98e0 | ||
|
fdae90ad9f | ||
|
744d0f7a3a | ||
|
f9f3674fde | ||
|
7d93d5dbfa | ||
|
e4e27d421a | ||
|
3645b14f3c | ||
|
dbd64f4545 | ||
|
53b9f8e4a3 | ||
|
1f44b48fde | ||
|
74ce672841 | ||
|
63265d5cfb | ||
|
bdc3832fd1 | ||
|
b72f78839c | ||
|
43568e947f | ||
|
3f1ca7ecc1 |
92 changed files with 1361 additions and 496 deletions
274
.clang-format
Normal file
274
.clang-format
Normal file
|
@ -0,0 +1,274 @@
|
|||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: true
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseArrows: false
|
||||
AlignCaseColons: false
|
||||
AlignConsecutiveTableGenBreakingDAGArgColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenCondOperatorColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenDefinitionColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowBreakBeforeNoexceptSpecifier: Never
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseExpressionOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterExternBlock: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAdjacentStringLiterals: true
|
||||
BreakAfterAttributes: Leave
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakAfterReturnType: None
|
||||
BreakArrays: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakFunctionDefinitionParameters: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
BreakTemplateDeclarations: MultiLine
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: false
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLines:
|
||||
AtEndOfFile: false
|
||||
AtStartOfBlock: true
|
||||
AtStartOfFile: true
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MainIncludeChar: Quote
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakScopeResolution: 500
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
QualifierAlignment: Leave
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SkipMacroDefinitionBody: false
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: true
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
ExceptDoubleParentheses: false
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TableGenBreakInsideDAGArg: DontBreak
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
...
|
||||
|
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
*.o
|
||||
*.d
|
||||
*a.out*
|
||||
build
|
||||
.cache/
|
||||
words.txt
|
||||
compile_commands.json
|
||||
lab2/edit
|
||||
lab2/spell
|
||||
lab3/tabletest
|
||||
./vscode
|
2
Makefile
Normal file
2
Makefile
Normal file
|
@ -0,0 +1,2 @@
|
|||
format:
|
||||
find . -regex '.*\.\(c\|cpp\|cc\|cxx\|h\|hpp\|hh\|hxx\)' -exec clang-format {} +
|
BIN
cpplabs.pdf
Normal file
BIN
cpplabs.pdf
Normal file
Binary file not shown.
2
lab1/.gitignore
vendored
Normal file
2
lab1/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
hello
|
||||
test_editor
|
51
lab1/Justfile
Normal file
51
lab1/Justfile
Normal file
|
@ -0,0 +1,51 @@
|
|||
all: a1 a2 a3 a4 cmake buggy
|
||||
|
||||
# Build the A1 lab exercise
|
||||
a1:
|
||||
g++ -o hello hello.cc
|
||||
./hello
|
||||
|
||||
# Build the A2 lab exercise
|
||||
a2:
|
||||
g++ -std=c++11 -o separate_main separate_main.cc separate_fn.cc
|
||||
|
||||
# Build the A3 lab exercise
|
||||
a3:
|
||||
g++ -std=c++11 -c separate_main.cc
|
||||
g++ -std=c++11 -c separate_fn.cc
|
||||
g++ -std=c++11 -o separate_main separate_main.o separate_fn.o
|
||||
|
||||
# Build the A4 lab exercise
|
||||
a4:
|
||||
@echo "Will fail"
|
||||
-g++ -std=c++11 -o separate_main separate_main.cc
|
||||
|
||||
# Build the A5 lab exercise
|
||||
a5:
|
||||
g++ -c -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast -std=c++11 hello.cc
|
||||
|
||||
# Build the cmake exercise
|
||||
cmake:
|
||||
rm -rf ./cmake-example/build # Start over
|
||||
cd ./cmake-example && mkdir -p build
|
||||
cd ./cmake-example/build && cmake ..
|
||||
cd ./cmake-example/build && make -j$(nproc)
|
||||
./cmake-example/build/SimpleMain
|
||||
|
||||
buggy:
|
||||
cd ./buggy_programs && make -j4
|
||||
cd ./buggy_programs && mkdir -p build
|
||||
cd ./buggy_programs && cmake -B build
|
||||
cd ./buggy_programs && make -C build
|
||||
|
||||
valgrind: buggy
|
||||
cd ./buggy_programs/build/ && valgrind ./dangling
|
||||
cd ./buggy_programs/build/ && valgrind ./bounds
|
||||
cd ./buggy_programs/build/ && valgrind ./bounds-heap
|
||||
cd ./buggy_programs/build/ && valgrind ./leak
|
||||
cd ./buggy_programs/build/ && valgrind ./sum
|
||||
cd ./buggy_programs/build/ && valgrind ./sum_alt
|
||||
cd ./buggy_programs/build/ && valgrind ./ub
|
||||
|
||||
clean:
|
||||
git clean -fdx
|
|
@ -1,58 +1,17 @@
|
|||
# Define the compiler and the linker. The linker must be defined since
|
||||
# the implicit rule for linking uses CC as the linker. g++ can be
|
||||
# changed to clang++.
|
||||
CXX = g++
|
||||
CC = $(CXX)
|
||||
|
||||
# Generate dependencies in *.d files
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
|
||||
|
||||
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
|
||||
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
|
||||
# -g is for debugging.
|
||||
CPPFLAGS = -std=c++11 -I.
|
||||
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
|
||||
CXXFLAGS += -std=c++11
|
||||
CXXFLAGS += -g
|
||||
CXXFLAGS += $(DEPFLAGS)
|
||||
LDFLAGS = -g
|
||||
#CPPFLAGS += -stdlib=libc++
|
||||
#CXXFLAGS += -stdlib=libc++
|
||||
#LDFLAGS += -stdlib=libc++
|
||||
|
||||
# Targets
|
||||
PROGS = test_editor test_coding print_argv hello encode decode
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
test: test_coding test_editor
|
||||
./test_coding
|
||||
./test_editor
|
||||
./hello
|
||||
|
||||
test_encode_decode: encode decode
|
||||
@echo "Running encode-decode tests"
|
||||
./encode testfile.txt
|
||||
./decode testfile.txt.enc
|
||||
|
||||
# Targets rely on implicit rules for compiling and linking
|
||||
print_argv: print_argv.o
|
||||
# The following rule means: "if test_editor does not exist, or
|
||||
# is older than test_editor.o or editor.o,
|
||||
# then link test_editor".
|
||||
test_editor: test_editor.o editor.o
|
||||
test_coding: test_coding.o coding.o
|
||||
encode: encode.o coding.o
|
||||
decode: decode.o coding.o
|
||||
g++ -o test_editor test_editor.o editor.o
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all test test_encode_decode clean distclean
|
||||
# Rules to create the object files.
|
||||
test_editor.o: test_editor.cc editor.h
|
||||
g++ -c test_editor.cc -std=c++11
|
||||
editor.o: editor.cc editor.h
|
||||
g++ -c editor.cc -std=c++11
|
||||
|
||||
# Standard clean
|
||||
clean:
|
||||
rm -f *.o $(PROGS)
|
||||
print_argv: print_argv.o
|
||||
g++ -o print_argv print_argv.o
|
||||
print_argv.o: print_argv.cc
|
||||
g++ -c print_argv.cc -std=c++11
|
||||
|
||||
distclean: clean
|
||||
rm *.d
|
||||
|
||||
|
||||
# Include the *.d files
|
||||
SRC = $(wildcard *.cc)
|
||||
-include $(SRC:.cc=.d)
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# The following rule means: "if test_editor does not exist, or
|
||||
# is older than test_editor.o or editor.o,
|
||||
# then link test_editor".
|
||||
test_editor: test_editor.o editor.o
|
||||
g++ -o test_editor test_editor.o editor.o
|
||||
|
||||
# Rules to create the object files.
|
||||
test_editor.o: test_editor.cc editor.h
|
||||
g++ -c test_editor.cc -std=c++11
|
||||
editor.o: editor.cc editor.h
|
||||
g++ -c editor.cc -std=c++11
|
||||
|
||||
print_argv: print_argv.o
|
||||
g++ -o print_argv print_argv.o
|
||||
print_argv.o: print_argv.cc
|
||||
g++ -c print_argv.cc -std=c++11
|
||||
|
50
lab1/MakefileWithDeps
Normal file
50
lab1/MakefileWithDeps
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Define the compiler and the linker. The linker must be defined since
|
||||
# the implicit rule for linking uses CC as the linker. g++ can be
|
||||
# changed to clang++.
|
||||
CXX = g++
|
||||
CC = $(CXX)
|
||||
|
||||
# Generate dependencies in *.d files
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $*.d
|
||||
|
||||
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
|
||||
# if you use clang++ and wish to use libc++ instead of GNU's libstdc++.
|
||||
# -g is for debugging.
|
||||
CPPFLAGS = -std=c++11 -I.
|
||||
CXXFLAGS = -O2 -Wall -Wextra -pedantic-errors -Wold-style-cast
|
||||
CXXFLAGS += -std=c++11
|
||||
CXXFLAGS += -g
|
||||
CXXFLAGS += $(DEPFLAGS)
|
||||
LDFLAGS = -g
|
||||
#CPPFLAGS += -stdlib=libc++
|
||||
#CXXFLAGS += -stdlib=libc++
|
||||
#LDFLAGS += -stdlib=libc++
|
||||
|
||||
# Targets
|
||||
PROGS = test_editor test_coding print_argv
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
test: test_coding test_editor
|
||||
./test_coding
|
||||
./test_editor
|
||||
|
||||
# Targets rely on implicit rules for compiling and linking
|
||||
print_argv: print_argv.o
|
||||
test_editor: test_editor.o editor.o
|
||||
test_coding: test_coding.o coding.o
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all test clean distclean
|
||||
|
||||
# Standard clean
|
||||
clean:
|
||||
rm -f *.o $(PROGS)
|
||||
|
||||
distclean: clean
|
||||
rm *.d
|
||||
|
||||
|
||||
# Include the *.d files
|
||||
SRC = $(wildcard *.cc)
|
||||
-include $(SRC:.cc=.d)
|
6
lab1/buggy_programs/.gitignore
vendored
Normal file
6
lab1/buggy_programs/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
bounds
|
||||
bounds-heap
|
||||
dangling
|
||||
leak
|
||||
sum
|
||||
ub
|
|
@ -3,7 +3,7 @@
|
|||
# It uses generator expressions, to set additional flags when the build type
|
||||
# is Debug.
|
||||
#
|
||||
# To try this out, first create a build directory for a release build,
|
||||
# To try this out, first create a build directory for a release build,
|
||||
# and do a release build, e.g.,
|
||||
# % mkdir build-rel
|
||||
# % cd build-rel
|
||||
|
@ -21,7 +21,7 @@
|
|||
#
|
||||
# where SRC_DIR is the directory containing the source and CMakeLists.txt,
|
||||
# e.g., .. if your build directories are placed in this directory.
|
||||
#
|
||||
#
|
||||
# Run the examples and verify that the sanitizers find the errors.
|
||||
#
|
||||
# If you want to see the actual commands run during the build, for instance
|
||||
|
|
|
@ -21,30 +21,20 @@ PROGS=ub leak bounds bounds-heap dangling sum
|
|||
ALL: $(PROGS)
|
||||
|
||||
leak: leak.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
dangling: dangling.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
bounds: bounds.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
ub: ub.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
sum: sum.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@ $<
|
||||
|
||||
# Targets
|
||||
# Phony targets
|
||||
.PHONY: all clean test
|
||||
|
||||
# Standard clean
|
||||
clean:
|
||||
-rm -f $(PROGS)
|
||||
-rm -rf $(addsuffix .dSYM, $(PROGS))
|
||||
|
||||
test: $(PROGS)
|
||||
@echo "Running tests with Valgrind..."
|
||||
@for prog in $(PROGS); do \
|
||||
echo "Testing $$prog with Valgrind:"; \
|
||||
valgrind ./$$prog; \
|
||||
echo ""; \
|
||||
done
|
||||
-rm $(PROGS)
|
||||
-rm -r $(addsuffix .dSYM, $(PROGS))
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
1
lab1/cmake-example/.gitignore
vendored
Normal file
1
lab1/cmake-example/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
build
|
|
@ -1,10 +1,9 @@
|
|||
#include<coding.h>
|
||||
#include <coding.h>
|
||||
|
||||
unsigned char encode(unsigned char c)
|
||||
{
|
||||
return c + 2;
|
||||
unsigned char encode(unsigned char c) {
|
||||
return ++c;
|
||||
}
|
||||
unsigned char decode(unsigned char c)
|
||||
{
|
||||
return c - 2;
|
||||
|
||||
unsigned char decode(unsigned char c) {
|
||||
return --c;
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
coding.o: coding.cc coding.h
|
||||
coding.h:
|
BIN
lab1/coding.o
BIN
lab1/coding.o
Binary file not shown.
BIN
lab1/decode
BIN
lab1/decode
Binary file not shown.
|
@ -1,34 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "coding.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string filename;
|
||||
|
||||
if (argc > 1) {
|
||||
filename = argv[1];
|
||||
} else {
|
||||
std::cout << "Enter filename to decode: ";
|
||||
std::cin >> filename;
|
||||
}
|
||||
|
||||
std::ifstream infile(filename, std::ios::binary);
|
||||
if (!infile) {
|
||||
std::cerr << "Could not open file " << filename << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::ofstream outfile(filename + ".dec", std::ios::binary);
|
||||
if (!outfile) {
|
||||
std::cerr << "Could not create output file" << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char c;
|
||||
while (infile.get(reinterpret_cast<char&>(c))) {
|
||||
outfile.put(decode(c));
|
||||
}
|
||||
|
||||
std::cout << "Decoding complete. Output saved to " << filename << ".dec" << "\n";
|
||||
return 0;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
decode.o: decode.cc coding.h
|
||||
coding.h:
|
BIN
lab1/decode.o
BIN
lab1/decode.o
Binary file not shown.
|
@ -6,29 +6,29 @@ using std::string;
|
|||
|
||||
using size_type = Editor::size_type;
|
||||
|
||||
size_type Editor::get_size() const
|
||||
{
|
||||
return text.size();
|
||||
}
|
||||
size_type Editor::get_size() const { return text.size(); }
|
||||
|
||||
size_type Editor::find_left_par(size_type pos) const {
|
||||
if (pos >= text.size() || (text[pos] != ')' && text[pos] != ']' && text[pos] != '}')) {
|
||||
return std::string::npos;
|
||||
Editor::size_type Editor::find_left_par(size_type pos) const {
|
||||
char right_par = text[pos];
|
||||
char left_par;
|
||||
|
||||
// Determine the matching left parenthesis for the given right parenthesis
|
||||
switch (right_par) {
|
||||
case ')': left_par = '('; break;
|
||||
case ']': left_par = '['; break;
|
||||
case '}': left_par = '{'; break;
|
||||
default: return string::npos; // Not a valid right parenthesis
|
||||
}
|
||||
|
||||
char right_par = text[pos];
|
||||
char left_par = (right_par == ')') ? '(' : (right_par == ']') ? '[' : '{';
|
||||
|
||||
int balance = 0;
|
||||
|
||||
for (int i = pos; i >= 0; --i) {
|
||||
if (text[i] == right_par) {
|
||||
balance++;
|
||||
} else if (text[i] == left_par) {
|
||||
int balance = 1; // Start with the right parenthesis at text[pos]
|
||||
for (size_type i = pos; i-- > 0;) {
|
||||
if (text[i] == left_par) {
|
||||
balance--;
|
||||
if (balance == 0) {
|
||||
return i;
|
||||
}
|
||||
if (balance == 0) return i; // Found the matching left parenthesis
|
||||
} else if (text[i] == right_par) {
|
||||
balance++;
|
||||
}
|
||||
}
|
||||
|
||||
return string::npos; // No matching left parenthesis found
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
editor.o: editor.cc editor.h
|
||||
editor.h:
|
|
@ -4,24 +4,24 @@
|
|||
#include <string>
|
||||
|
||||
class Editor {
|
||||
public:
|
||||
public:
|
||||
using size_type = std::string::size_type;
|
||||
/* Creates a text editor containing the text t */
|
||||
Editor(const std::string& t) : text(t) {}
|
||||
/* Creates a text editor containing the text t */
|
||||
Editor(const std::string &t) : text(t) {}
|
||||
|
||||
/* Get the size of the current contents */
|
||||
size_type get_size() const;
|
||||
|
||||
/*
|
||||
* Text[pos] contains a right parentheses. Returns the position of
|
||||
* the corresponding left parentheses, or string::npos if there
|
||||
* is no match.
|
||||
*/
|
||||
size_type find_left_par(size_type pos) const;
|
||||
/*
|
||||
* Text[pos] contains a right parentheses. Returns the position of
|
||||
* the corresponding left parentheses, or string::npos if there
|
||||
* is no match.
|
||||
*/
|
||||
size_type find_left_par(size_type pos) const;
|
||||
|
||||
// ... functions to edit the text (insert and delete characters)
|
||||
private:
|
||||
std::string text;
|
||||
// ... functions to edit the text (insert and delete characters)
|
||||
private:
|
||||
std::string text;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
BIN
lab1/editor.o
BIN
lab1/editor.o
Binary file not shown.
BIN
lab1/encode
BIN
lab1/encode
Binary file not shown.
|
@ -1,35 +0,0 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "coding.h"
|
||||
|
||||
int main (int argc, char* argv[]) {
|
||||
std::string filename;
|
||||
|
||||
if (argc > 1) {
|
||||
filename = argv[1];
|
||||
} else {
|
||||
std::cout << "Enter filename: ";
|
||||
std::cin >> filename;
|
||||
}
|
||||
|
||||
std::ifstream infile(filename, std::ios::binary);
|
||||
if (!infile) {
|
||||
std::cerr << "Could not open file " << filename << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string output_filename = filename + ".enc";
|
||||
std::ofstream outfile(output_filename, std::ios::binary);
|
||||
if (!outfile) {
|
||||
std::cerr << "Could not create output file" << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char c;
|
||||
while (infile.get(reinterpret_cast<char&>(c))) {
|
||||
outfile.put(encode(c));
|
||||
}
|
||||
|
||||
std::cout << "Encoding complete. Output saved to " << filename << "\n";
|
||||
return 0;
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
encode.o: encode.cc coding.h
|
||||
coding.h:
|
BIN
lab1/encode.o
BIN
lab1/encode.o
Binary file not shown.
BIN
lab1/hello
BIN
lab1/hello
Binary file not shown.
|
@ -1,7 +1,5 @@
|
|||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello, World!" << "\n";
|
||||
std::cout << "Hello, World!" << "\n";
|
||||
return 0;
|
||||
}
|
||||
int main(int argc, char *argv[]) {
|
||||
std::cout << "Hello" << std::endl;
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
hello: hello.cc
|
BIN
lab1/print_argv
BIN
lab1/print_argv
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
print_argv.o: print_argv.cc
|
Binary file not shown.
|
@ -1,49 +0,0 @@
|
|||
1. What is the difference between a declaration and a definition?
|
||||
|
||||
A declaration tells the compiler about the existence of a variable or function,
|
||||
while a definition allocates storage or provides the function code.
|
||||
|
||||
|
||||
2. How does an include guard prevent multiple definitions?
|
||||
|
||||
An include guard (using #ifndef, #define, #endif)
|
||||
prevents a header file from being included multiple times, which avoids redefinitions.
|
||||
|
||||
|
||||
3. How can you tell if an error comes from the compiler or the linker? Does a linker error
|
||||
mean that you have an error in your source code? How do you (typically) fix a linker error?
|
||||
|
||||
Compiler errors are syntax or semantic issues in code, while linker errors occur when symbols
|
||||
are missing or duplicated across files. A linker error often means a missing definition or library; it’s fixed by ensuring all functions and variables are correctly defined and linked.
|
||||
|
||||
|
||||
4. Do you have to make any changes to MakefileWithDeps to build your hello world program?
|
||||
|
||||
You may need to adjust MakefileWithDeps
|
||||
if dependencies or file paths change for your hello world program.
|
||||
|
||||
|
||||
5. In encode and decode, the type unsigned char is used. Would your code work the same
|
||||
way if that type is changed to char or signed char?
|
||||
|
||||
Changing unsigned char to char or signed char
|
||||
may alter the behavior due to differences in handling negative values.
|
||||
|
||||
|
||||
6. In the coding problem, reading the file with char ch; while (infile >> ch) ... doesn’t
|
||||
work. Why?
|
||||
|
||||
infile >> ch reads formatted input, skipping whitespace;
|
||||
using infile.get(ch) reads every character, including whitespace.
|
||||
|
||||
|
||||
7. If your program crashes, how can you use the debugger to get a stack trace similar to that
|
||||
of Exception.printStackTrace() in Java?
|
||||
|
||||
lldb ./progrma -> run -> bt
|
||||
|
||||
|
||||
8. What is the difference between a debugger breakpoint and a watchpoint?
|
||||
|
||||
A breakpoint pauses execution at a specific line,
|
||||
while a watchpoint stops execution when a specific variable changes.
|
|
@ -25,8 +25,6 @@ PROGS = read-words example-out
|
|||
|
||||
all: $(PROGS)
|
||||
|
||||
test: ./example-out ./read-words
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all test clean distclean
|
||||
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
And this is written to stderr
|
||||
And some more to stderr
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
example-out: example-out.cc
|
|
@ -1,2 +0,0 @@
|
|||
This text is written to stdout
|
||||
More text to stdout
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
read-words: read-words.cc
|
BIN
lab1/test_coding
BIN
lab1/test_coding
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
test_coding.o: test_coding.cc coding.h
|
||||
coding.h:
|
Binary file not shown.
BIN
lab1/test_editor
BIN
lab1/test_editor
Binary file not shown.
|
@ -1,2 +0,0 @@
|
|||
test_editor.o: test_editor.cc editor.h
|
||||
editor.h:
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
Hello my name is Douglas
|
|
@ -1 +0,0 @@
|
|||
Fcjjmkwl_kcgqBmsej_q
|
|
@ -1 +0,0 @@
|
|||
Jgnnq"o{"pcog"ku"Fqwincu
|
|
@ -1 +0,0 @@
|
|||
Hello my name is Douglas
|
37
lab2/Makefile
Normal file
37
lab2/Makefile
Normal file
|
@ -0,0 +1,37 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -Wall -Wextra -Wpedantic -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -std=c++17
|
||||
#CXXFLAGS += -Werror
|
||||
|
||||
SRC = $(wildcard *.cc)
|
||||
HDR = $(wildcard *.h)
|
||||
OBJ = $(SRC:.cc=.o)
|
||||
|
||||
all: spell edit $(OBJ)
|
||||
|
||||
edit: test_edit_distance.o edit_distance.o
|
||||
@echo "Building & linking $@"
|
||||
@$(CXX) $(CXXFLAGS) $^ -o $@
|
||||
|
||||
spell: spell.o word.o dictionary.o edit_distance.o
|
||||
@echo "Building & linking $@"
|
||||
@$(CXX) $(CXXFLAGS) $^ -o $@
|
||||
|
||||
%.o:%.cc
|
||||
@echo "Building $@"
|
||||
@$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
||||
lint: clang-tidy cppcheck clang-format
|
||||
|
||||
clang-tidy:
|
||||
clang-tidy $(SRC) -- $(CXXFLAGS)
|
||||
|
||||
cppcheck:
|
||||
cppcheck --enable=all --language=c++ --std=c++17 --suppress=missingIncludeSystem -I/usr/include $(SRC) $(HDR)
|
||||
|
||||
clang-format:
|
||||
clang-format -i $(SRC) $(HDR)
|
||||
|
||||
clean:
|
||||
rm -f *.o spell edit
|
||||
|
||||
.PHONY: clean all lint clang-tidy cppcheck clang-format
|
|
@ -1,22 +1,131 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include "dictionary.h"
|
||||
#include "edit_distance.h"
|
||||
#include "word.h"
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include "word.h"
|
||||
#include "dictionary.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
Dictionary::Dictionary() {
|
||||
Dictionary::Dictionary() {}
|
||||
|
||||
bool Dictionary::contains(const string &word) const {
|
||||
auto l = word.length();
|
||||
Word w = Word(word);
|
||||
if (std::find(this->words[l].begin(), this->words[l].end(), w) !=
|
||||
std::end(this->words[l])) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Dictionary::contains(const string& word) const {
|
||||
return true;
|
||||
std::vector<string> Dictionary::get_suggestions(const string &word) const {
|
||||
vector<string> suggestions;
|
||||
add_trigram_suggestions(suggestions, word);
|
||||
trim_suggestions(suggestions, word);
|
||||
rank_suggestions(suggestions, word);
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
vector<string> Dictionary::get_suggestions(const string& word) const {
|
||||
vector<string> suggestions;
|
||||
return suggestions;
|
||||
void Dictionary::add_trigram_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Get trigrams of the input word
|
||||
Word input_word(word);
|
||||
const std::vector<std::string> &input_trigrams = input_word.get_trigrams();
|
||||
|
||||
// Iterate through all words in the dictionary
|
||||
for (int i = 0; i < MAXLEN; ++i) {
|
||||
for (const Word &dict_word : words[i]) {
|
||||
// Get the trigrams of the dictionary word
|
||||
const std::vector<std::string> &dict_word_trigrams =
|
||||
dict_word.get_trigrams();
|
||||
|
||||
// Count how many trigrams match
|
||||
unsigned int match_count = dict_word.get_matches(input_trigrams);
|
||||
|
||||
// If there are any matches, add the word to suggestions
|
||||
if (match_count > 0) {
|
||||
suggestions.push_back(dict_word.get_word());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dictionary::rank_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Sort suggestions based on the levenshtein distance
|
||||
std::sort(suggestions.begin(), suggestions.end(),
|
||||
[&](const std::string &a, const std::string &b) {
|
||||
auto dist_a = edit_distance(a, word);
|
||||
auto dist_b = edit_distance(b, word);
|
||||
return dist_a < dist_b;
|
||||
});
|
||||
}
|
||||
|
||||
void Dictionary::trim_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const {
|
||||
// Remove duplicates using a set
|
||||
std::set<std::string> unique_suggestions(suggestions.begin(),
|
||||
suggestions.end());
|
||||
suggestions.assign(unique_suggestions.begin(), unique_suggestions.end());
|
||||
|
||||
// Remove the input word from the suggestions list (if present)
|
||||
suggestions.erase(std::remove(suggestions.begin(), suggestions.end(), word),
|
||||
suggestions.end());
|
||||
|
||||
auto l = word.length();
|
||||
std::cout << "WTF" << l << std::endl;
|
||||
|
||||
// Example: Remove any suggestions that are not within 1 string length
|
||||
suggestions.erase(std::remove_if(suggestions.begin(), suggestions.end(),
|
||||
[l](const std::string &s) {
|
||||
return s.length() > (l + 1) ||
|
||||
s.length() < (l - 1);
|
||||
}),
|
||||
suggestions.end());
|
||||
}
|
||||
|
||||
int Dictionary::spit(path p) {
|
||||
std::ofstream file(p);
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file! " << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int a = 0; a < MAXLEN; a++) {
|
||||
for (auto &word : words[a]) {
|
||||
file << word;
|
||||
file << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
file.flush();
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dictionary::slurp(path p) {
|
||||
std::ifstream file(p.string());
|
||||
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Error opening file! " << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(file, line)) {
|
||||
if (line.empty())
|
||||
continue;
|
||||
// Words larger than max gets placed in the topmost bucket
|
||||
words[std::min(line.size(), static_cast<size_t>(MAXLEN) - 1)].push_back(
|
||||
Word(line));
|
||||
}
|
||||
|
||||
file.close();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,29 @@
|
|||
#ifndef DICTIONARY_H
|
||||
#define DICTIONARY_H
|
||||
#pragma once
|
||||
|
||||
#include "word.h"
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Dictionary {
|
||||
public:
|
||||
Dictionary();
|
||||
bool contains(const std::string& word) const;
|
||||
std::vector<std::string> get_suggestions(const std::string& word) const;
|
||||
private:
|
||||
};
|
||||
#define MAXLEN 30
|
||||
|
||||
#endif
|
||||
// using std::vector;
|
||||
using std::filesystem::path;
|
||||
|
||||
class Dictionary {
|
||||
public:
|
||||
Dictionary();
|
||||
void add_trigram_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
void rank_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
void trim_suggestions(std::vector<std::string> &suggestions,
|
||||
const std::string &word) const;
|
||||
bool contains(const std::string &word) const;
|
||||
std::vector<std::string> get_suggestions(const std::string &word) const;
|
||||
int slurp(path p);
|
||||
int spit(path p);
|
||||
|
||||
private:
|
||||
std::vector<Word> words[MAXLEN];
|
||||
};
|
||||
|
|
35
lab2/edit_distance.cc
Normal file
35
lab2/edit_distance.cc
Normal file
|
@ -0,0 +1,35 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
int edit_distance(const std::string &s1, const std::string &s2) {
|
||||
size_t m = s1.size();
|
||||
size_t n = s2.size();
|
||||
|
||||
// Create a 2D DP table
|
||||
std::vector<std::vector<size_t>> dp(m + 1, std::vector<size_t>(n + 1));
|
||||
|
||||
// Fill the base cases
|
||||
for (size_t i = 0; i <= m; ++i)
|
||||
dp[i][0] = i; // Deletion cost
|
||||
|
||||
for (size_t j = 0; j <= n; ++j)
|
||||
dp[0][j] = j; // Insertion cost
|
||||
|
||||
// Fill the DP table
|
||||
for (size_t i = 1; i <= m; ++i) {
|
||||
for (size_t j = 1; j <= n; ++j) {
|
||||
if (s1[i - 1] == s2[j - 1]) {
|
||||
dp[i][j] = dp[i - 1][j - 1]; // No operation needed
|
||||
} else {
|
||||
dp[i][j] = 1 + std::min({
|
||||
dp[i - 1][j], // Deletion
|
||||
dp[i][j - 1], // Insertion
|
||||
dp[i - 1][j - 1] // Substitution
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<int>(dp[m][n]);
|
||||
}
|
17
lab2/edit_distance.h
Normal file
17
lab2/edit_distance.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Computes the edit distance (Levenshtein distance) between two strings.
|
||||
*
|
||||
* The edit distance is defined as the minimum number of single-character edits
|
||||
* (insertions, deletions, or substitutions) required to transform one string
|
||||
* into the other.
|
||||
*
|
||||
* This implementation uses dynamic programming to compute the distance
|
||||
* efficiently.
|
||||
*
|
||||
* @param s1 The first string.
|
||||
* @param s2 The second string.
|
||||
* @return The edit distance between the two strings.
|
||||
*/
|
||||
int edit_distance(const std::string &s1, const std::string &s2);
|
|
@ -1,18 +1,18 @@
|
|||
#include "dictionary.h"
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
#include "dictionary.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
void check_word(const string& word, const Dictionary& dict)
|
||||
{
|
||||
void check_word(const string &word, const Dictionary &dict) {
|
||||
if (dict.contains(word)) {
|
||||
cout << "Correct." << endl;
|
||||
} else {
|
||||
|
@ -21,18 +21,22 @@ void check_word(const string& word, const Dictionary& dict)
|
|||
cout << "Wrong, no suggestions." << endl;
|
||||
} else {
|
||||
cout << "Wrong. Suggestions:" << endl;
|
||||
for (const auto& w : suggestions) {
|
||||
for (const auto &w : suggestions) {
|
||||
cout << " " << w << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
Dictionary dict;
|
||||
string word;
|
||||
while (cin >> word) {
|
||||
transform(word.begin(), word.end(), word.begin(), ::tolower);
|
||||
Dictionary dict;
|
||||
string word;
|
||||
dict.slurp(std::filesystem::path("/usr/share/dict/words"));
|
||||
// dict.spit(std::filesystem::path("words.txt"));
|
||||
|
||||
while (cin >> word) {
|
||||
std::transform(word.begin(), word.end(), word.begin(), ::tolower);
|
||||
check_word(word, dict);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
bool do_test(const std::string& x, const std::string& y, int expected)
|
||||
{
|
||||
bool do_test(const std::string &x, const std::string &y, int expected) {
|
||||
auto actual = edit_distance(x, y);
|
||||
if (actual != expected) {
|
||||
std::cout << "*** WRONG: distance(" << x << ", " << y << ") was "
|
||||
|
@ -19,8 +18,7 @@ bool do_test(const std::string& x, const std::string& y, int expected)
|
|||
return false;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int main() {
|
||||
int res = do_test("foobar", "foobar", 0);
|
||||
res += do_test("x", "x", 0);
|
||||
res += do_test("baz", "bar", 1);
|
||||
|
|
63
lab2/word.cc
63
lab2/word.cc
|
@ -1,16 +1,63 @@
|
|||
#include "word.h"
|
||||
#include "dictionary.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "word.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
Word::Word(const string& w, const vector<string>& t) {}
|
||||
|
||||
string Word::get_word() const {
|
||||
return string();
|
||||
Word::Word(const string &w, const vector<string> &t) : word(w), trigrams(t) {
|
||||
std::sort(trigrams.begin(), trigrams.end());
|
||||
}
|
||||
|
||||
unsigned int Word::get_matches(const vector<string>& t) const {
|
||||
return 0;
|
||||
std::vector<std::string> get_trigrams(const std::string &text) {
|
||||
std::vector<std::string> trigrams;
|
||||
if (text.size() < 3) {
|
||||
return trigrams; // Return an empty vector if the input is too short
|
||||
}
|
||||
|
||||
for (size_t i = 0; i <= text.size() - 3; ++i) {
|
||||
trigrams.push_back(
|
||||
text.substr(i, 3)); // Extract a substring of length 3
|
||||
}
|
||||
|
||||
return trigrams;
|
||||
}
|
||||
|
||||
Word::Word(const std::string &w) : word(w) {
|
||||
this->trigrams = ::get_trigrams(w);
|
||||
std::sort(trigrams.begin(), trigrams.end());
|
||||
}
|
||||
|
||||
string Word::get_word() const { return word; }
|
||||
|
||||
vector<std::string> Word::get_trigrams() const { return trigrams; }
|
||||
|
||||
unsigned int Word::get_matches(const vector<string> &t) const {
|
||||
unsigned int matches = 0;
|
||||
|
||||
for (const auto &trigram : t) {
|
||||
if (std::binary_search(trigrams.begin(), trigrams.end(), trigram)) {
|
||||
++matches;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Word &w) {
|
||||
auto space = string(" ");
|
||||
out << w.word;
|
||||
out << space;
|
||||
out << w.trigrams.size();
|
||||
for (const auto &tri : w.trigrams) {
|
||||
out << space << tri;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool operator==(const Word &lhs, const Word &rhs) {
|
||||
return lhs.word == rhs.word &&
|
||||
std::equal(lhs.trigrams.begin(), lhs.trigrams.end(),
|
||||
rhs.trigrams.begin());
|
||||
}
|
||||
|
|
41
lab2/word.h
41
lab2/word.h
|
@ -1,21 +1,34 @@
|
|||
#ifndef WORD_H
|
||||
#define WORD_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
* Contains a word and its trigrams
|
||||
*/
|
||||
class Word {
|
||||
public:
|
||||
/* Creates a word w with the sorted trigrams t */
|
||||
Word(const std::string& w, const std::vector<std::string>& t);
|
||||
|
||||
/* Returns the word */
|
||||
std::string get_word() const;
|
||||
|
||||
/* Returns how many of the trigrams in t that are present
|
||||
in this word's trigram vector */
|
||||
unsigned int get_matches(const std::vector<std::string>& t) const;
|
||||
private:
|
||||
public:
|
||||
/** Creates a word w with the sorted trigrams t */
|
||||
Word(const std::string &w, const std::vector<std::string> &t);
|
||||
|
||||
/** Creates a word w and derives the trigrams internally */
|
||||
Word(const std::string &w);
|
||||
|
||||
/** Returns the word */
|
||||
std::string get_word() const;
|
||||
|
||||
/** Returns trigrams */
|
||||
std::vector<std::string> get_trigrams() const;
|
||||
|
||||
/** Returns how many of the trigrams in t that are present
|
||||
in this word's trigram vector */
|
||||
unsigned int get_matches(const std::vector<std::string> &t) const;
|
||||
|
||||
private:
|
||||
const std::string word;
|
||||
std::vector<std::string> trigrams;
|
||||
friend std::ostream &operator<<(std::ostream &out, const Word &o);
|
||||
friend bool operator==(const Word &lhs, const Word &rhs);
|
||||
};
|
||||
|
||||
#endif
|
||||
bool operator==(const Word &lhs, const Word &rhs);
|
||||
|
|
33
lab3/Makefile
Normal file
33
lab3/Makefile
Normal file
|
@ -0,0 +1,33 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -Wall -Wextra -Wpedantic -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused -Woverloaded-virtual -Wconversion -Wsign-conversion -Wnull-dereference -Wdouble-promotion -Wformat=2 -std=c++17
|
||||
#CXXFLAGS += -Werror
|
||||
|
||||
SRC = $(wildcard *.cc)
|
||||
HDR = $(wildcard *.h)
|
||||
OBJ = $(SRC:.cc=.o)
|
||||
|
||||
all: tabletest $(OBJ)
|
||||
|
||||
tabletest: $(OBJ)
|
||||
@echo "Building & linking $@"
|
||||
@$(CXX) $(CXXFLAGS) $^ -o $@
|
||||
|
||||
%.o:%.cc
|
||||
@echo "Building $@"
|
||||
@$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
||||
lint: clang-tidy cppcheck clang-format
|
||||
|
||||
clang-tidy:
|
||||
clang-tidy $(SRC) -- $(CXXFLAGS)
|
||||
|
||||
cppcheck:
|
||||
cppcheck --enable=all --language=c++ --std=c++17 --suppress=missingIncludeSystem -I/usr/include $(SRC) $(HDR)
|
||||
|
||||
clang-format:
|
||||
clang-format -i $(SRC) $(HDR)
|
||||
|
||||
clean:
|
||||
rm -f *.o spell edit
|
||||
|
||||
.PHONY: clean all lint clang-tidy cppcheck clang-format
|
|
@ -1,6 +1,5 @@
|
|||
#include "User.h"
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const User& u)
|
||||
{
|
||||
return os << "(" << u.getCardNbr() << ") "<< u.getName();
|
||||
std::ostream &operator<<(std::ostream &os, const User &u) {
|
||||
return os << "(" << u.getCardNbr() << ") " << u.getName();
|
||||
}
|
||||
|
|
30
lab3/User.h
30
lab3/User.h
|
@ -8,20 +8,26 @@ using std::cout;
|
|||
using std::endl;
|
||||
|
||||
class User {
|
||||
public:
|
||||
User() :cardNbr{0},name{"default"}{}
|
||||
User(int c, std::string n) :cardNbr{c},name{n} {}
|
||||
~User() {cardNbr=-2; name="--------------------";} // overwrite values for security reasons
|
||||
User(const User& u) =default;
|
||||
User& operator=(const User&) =default;
|
||||
int getCardNbr() const {return cardNbr;}
|
||||
std::string getName() const {return name;}
|
||||
bool operator==(const User& u) const {return cardNbr == u.cardNbr && name == u.name;}
|
||||
bool operator!=(const User& u) const {return ! (u == *this);}
|
||||
private:
|
||||
public:
|
||||
User() : cardNbr{0}, name{"default"} {}
|
||||
User(int c, std::string n) : cardNbr{c}, name{n} {}
|
||||
~User() {
|
||||
cardNbr = -2;
|
||||
name = "--------------------";
|
||||
} // overwrite values for security reasons
|
||||
User(const User &u) = default;
|
||||
User &operator=(const User &) = default;
|
||||
int getCardNbr() const { return cardNbr; }
|
||||
std::string getName() const { return name; }
|
||||
bool operator==(const User &u) const {
|
||||
return cardNbr == u.cardNbr && name == u.name;
|
||||
}
|
||||
bool operator!=(const User &u) const { return !(u == *this); }
|
||||
|
||||
private:
|
||||
int cardNbr;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const User& u);
|
||||
std::ostream &operator<<(std::ostream &os, const User &u);
|
||||
#endif
|
||||
|
|
|
@ -1,24 +1,22 @@
|
|||
#include "UserTable.h"
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
|
||||
const User UserTable::user_not_found = User{-1,"Not Found"};
|
||||
const User UserTable::user_not_found = User{-1, "Not Found"};
|
||||
|
||||
UserTable::UserTable() :users{new User[capacity]} { }
|
||||
UserTable::UserTable() : users{new User[capacity]} {}
|
||||
|
||||
UserTable::UserTable(const std::string& fname) :UserTable{}
|
||||
{
|
||||
UserTable::UserTable(const std::string &fname) : UserTable{} {
|
||||
std::ifstream ufile(fname);
|
||||
|
||||
if(ufile.is_open()) {
|
||||
while(ufile) {
|
||||
if (ufile.is_open()) {
|
||||
while (ufile) {
|
||||
int cn;
|
||||
if(ufile >> cn ) {
|
||||
if (ufile >> cn) {
|
||||
ufile.ignore(); // skip space
|
||||
char n[80];
|
||||
ufile.getline(n,80);
|
||||
addUser(User(cn,n));
|
||||
|
||||
ufile.getline(n, 80);
|
||||
addUser(User(cn, n));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -26,38 +24,39 @@ UserTable::UserTable(const std::string& fname) :UserTable{}
|
|||
}
|
||||
}
|
||||
|
||||
void UserTable::addUser(const User& u)
|
||||
{
|
||||
void UserTable::addUser(const User &u) {
|
||||
// gör tabellen större vid behov
|
||||
ensureCapacity(n+1);
|
||||
ensureCapacity(n + 1);
|
||||
|
||||
// 1. Hitta rätt plats
|
||||
int pos{0};
|
||||
while ( (pos < n) && (users[pos].getCardNbr() < u.getCardNbr())){
|
||||
while ((pos < n) && (users[pos].getCardNbr() < u.getCardNbr())) {
|
||||
++pos;
|
||||
}
|
||||
|
||||
//2. skapa lucka i vektorn
|
||||
for(int i=n; i > pos; --i){
|
||||
users[i] = users[i-1];
|
||||
// 2. skapa lucka i vektorn
|
||||
for (int i = n; i > pos; --i) {
|
||||
users[i] = users[i - 1];
|
||||
}
|
||||
|
||||
//3. stoppa in den nya användaren i luckan
|
||||
// 3. stoppa in den nya användaren i luckan
|
||||
users[pos] = u;
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
User UserTable::find(int c) const
|
||||
{
|
||||
User UserTable::find(int c) const {
|
||||
// binärsökning (baserad på Holm, 2007)
|
||||
|
||||
int low = 0;
|
||||
int high = n - 1;
|
||||
int mid = -1;
|
||||
bool found = false;
|
||||
while (low < high && ! found) {
|
||||
while (low < high && !found) {
|
||||
mid = (low + high) / 2;
|
||||
//
|
||||
int midnbr = users[mid].getCardNbr();
|
||||
if (midnbr = c) {
|
||||
const int midnbr = users[mid].getCardNbr();
|
||||
if (c == midnbr) {
|
||||
found = true;
|
||||
} else if (users[mid].getCardNbr() < c) {
|
||||
low = mid + 1;
|
||||
|
@ -68,48 +67,41 @@ User UserTable::find(int c) const
|
|||
|
||||
return found ? users[mid] : user_not_found;
|
||||
}
|
||||
User UserTable::find(std::string name) const
|
||||
{
|
||||
for (int i = 0; i != n; ++i) {
|
||||
if (users[i].getName() == name) {
|
||||
return users[i];
|
||||
} else {
|
||||
return user_not_found;
|
||||
}
|
||||
}
|
||||
return user_not_found;
|
||||
User UserTable::find(std::string name) const {
|
||||
auto it = std::find_if(users, users + n, [&name](const User &u) {
|
||||
return u.getName() == name;
|
||||
});
|
||||
|
||||
// If it is at the 'end' of users, the result is not found
|
||||
return (it != users+n) ? *it : user_not_found;
|
||||
}
|
||||
|
||||
void UserTable::ensureCapacity(int s)
|
||||
{
|
||||
if(s>capacity) {
|
||||
while(s > capacity) {
|
||||
capacity*=4;
|
||||
void UserTable::ensureCapacity(int s) {
|
||||
if (s > capacity) {
|
||||
while (s > capacity) {
|
||||
capacity *= 4;
|
||||
}
|
||||
auto tmp = new User[capacity];
|
||||
std::copy(users, users+n, tmp);
|
||||
std::copy(users, users + n, tmp);
|
||||
delete[] users;
|
||||
users=tmp;
|
||||
users = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
void UserTable::print(std::ostream& os) const
|
||||
{
|
||||
void UserTable::print(std::ostream &os) const {
|
||||
os << "-------------" << std::endl;
|
||||
for(int i = 0; i != getNbrUsers(); ++i) {
|
||||
const auto& u = users[i];
|
||||
os << "(" <<u.getCardNbr() << ") " << u.getName() << std::endl;
|
||||
for (int i = 0; i != getNbrUsers(); ++i) {
|
||||
const auto &u = users[i];
|
||||
os << "(" << u.getCardNbr() << ") " << u.getName() << std::endl;
|
||||
}
|
||||
os << "=============" << std::endl;
|
||||
}
|
||||
/**
|
||||
* Testmetod för binärsökningen:
|
||||
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
|
||||
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
|
||||
* alla sökningar lyckades, returneras 0.
|
||||
*/
|
||||
int testFindNbr(const UserTable ut)
|
||||
{
|
||||
* Testmetod för binärsökningen:
|
||||
* går igenom alla användare och kollar att deras kortnummer kan sökas upp.
|
||||
* Om något kortnummer inte kunde sökas upp returneras detta. Annars, om
|
||||
* alla sökningar lyckades, returneras 0.
|
||||
*/
|
||||
int testFindNbr(const UserTable ut) {
|
||||
for (int i = 0; i < ut.n; i++) {
|
||||
int nbr = ut.users[i].getCardNbr();
|
||||
User found = ut.find(nbr);
|
||||
|
@ -119,4 +111,3 @@ int testFindNbr(const UserTable ut)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,28 +5,27 @@
|
|||
|
||||
#include "User.h"
|
||||
|
||||
class UserTable{
|
||||
public:
|
||||
class UserTable {
|
||||
public:
|
||||
UserTable();
|
||||
UserTable(const std::string&);
|
||||
~UserTable() {delete[] users;}
|
||||
UserTable(const std::string &);
|
||||
~UserTable() { delete[] users; }
|
||||
|
||||
void addUser(const User&);
|
||||
void addUser(const User &);
|
||||
User find(int) const;
|
||||
User find(std::string) const;
|
||||
|
||||
int getNbrUsers() const {
|
||||
return n;
|
||||
}
|
||||
int getNbrUsers() const { return n; }
|
||||
|
||||
void print(std::ostream&) const;
|
||||
void print(std::ostream &) const;
|
||||
|
||||
static const User user_not_found;
|
||||
private:
|
||||
|
||||
private:
|
||||
int capacity{1000};
|
||||
void ensureCapacity(int);
|
||||
int n{0};
|
||||
User* users;
|
||||
User *users;
|
||||
|
||||
friend int testFindNbr(const UserTable ut);
|
||||
};
|
||||
|
|
42
lab3/UserTableTest.cc
Normal file
42
lab3/UserTableTest.cc
Normal file
|
@ -0,0 +1,42 @@
|
|||
#include "UserTable.h"
|
||||
#include "User.h"
|
||||
#include <cassert>
|
||||
|
||||
int main() {
|
||||
{ /* User Related Tests */
|
||||
// Two identical users
|
||||
User u1 = User(1234, "Name Nameson");
|
||||
User u2 = User(1234, "Name Nameson");
|
||||
|
||||
assert(u1.getName() == u2.getName());
|
||||
assert(u1.getCardNbr() == u2.getCardNbr());
|
||||
|
||||
// Two different users
|
||||
User u3 = User(1200, "Name Surname");
|
||||
User u4 = User(1201, "Name Nameson");
|
||||
|
||||
assert(u3.getName() != u4.getName());
|
||||
assert(u3.getCardNbr() != u4.getCardNbr());
|
||||
}
|
||||
{ /* Table Related Tests */
|
||||
UserTable tbl1 = UserTable();
|
||||
assert(tbl1.find("Jens Holmgren") == UserTable::user_not_found);
|
||||
tbl1.addUser(User(1200, "Table Yes"));
|
||||
assert(tbl1.getNbrUsers() == 1);
|
||||
}
|
||||
{
|
||||
// Assumes 'users.txt' is present, containing
|
||||
// line separated records formatted as:
|
||||
// "89524 Adam Abrahamsson"
|
||||
UserTable tbl = UserTable("users.txt");
|
||||
assert(tbl.getNbrUsers() > 0);
|
||||
assert(tbl.find("Jens Holmgren") != UserTable::user_not_found);
|
||||
|
||||
tbl.addUser(User(1200, "Name Surname"));
|
||||
User ufind1 = tbl.find(1200);
|
||||
assert(ufind1 != UserTable::user_not_found);
|
||||
|
||||
User ufind2 = tbl.find("Name Surname");
|
||||
assert(ufind2 != UserTable::user_not_found);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"charconv": "cpp",
|
||||
"clocale": "cpp",
|
||||
|
@ -31,13 +32,13 @@
|
|||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"regex": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"format": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
74
lab4/Sieve.cc
Normal file
74
lab4/Sieve.cc
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Sieve {
|
||||
private:
|
||||
std::string sieve;
|
||||
|
||||
public:
|
||||
// Constructor to initialize sieve with 'P' (prime assumption)
|
||||
Sieve(size_t limit) : sieve(limit + 1, 'P') {
|
||||
// 0 and 1 are not primes
|
||||
sieve[0] = 'C';
|
||||
if (limit > 0) sieve[1] = 'C';
|
||||
|
||||
// Sieve of Eratosthenes
|
||||
for (size_t i = 2; i * i <= limit; ++i) {
|
||||
if (sieve[i] == 'P') {
|
||||
for (size_t j = i * i; j <= limit; j += i) {
|
||||
sieve[j] = 'C';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get primes as a vector of integers
|
||||
std::vector<int> getPrimes() const {
|
||||
std::vector<int> primes;
|
||||
for (size_t i = 2; i < sieve.size(); ++i) {
|
||||
if (sieve[i] == 'P') {
|
||||
primes.push_back(i);
|
||||
}
|
||||
}
|
||||
return primes;
|
||||
}
|
||||
|
||||
// Print all primes in the range
|
||||
void printPrimesInRange(int start, int end) const {
|
||||
for (int i = start; i <= end; ++i) {
|
||||
if (sieve[i] == 'P') {
|
||||
std::cout << i << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// Get the largest prime below a limit
|
||||
int largestPrimeBelow(int limit) const {
|
||||
for (int i = limit; i >= 2; --i) {
|
||||
if (sieve[i] == 'P') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1; // If no prime is found
|
||||
}
|
||||
};
|
||||
|
||||
// Main function for testing
|
||||
int main() {
|
||||
const int limit = 100000;
|
||||
|
||||
// Create a Sieve instance for the range 0 to limit
|
||||
Sieve sieve(limit);
|
||||
|
||||
// Print primes between 1 and 200
|
||||
std::cout << "Primes between 1 and 200:" << std::endl;
|
||||
sieve.printPrimesInRange(1, 200);
|
||||
|
||||
// Find and print the largest prime below 100,000
|
||||
int largestPrime = sieve.largestPrimeBelow(limit);
|
||||
std::cout << "Largest prime below " << limit << ": " << largestPrime << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
32
lab4/TagRemover.cc
Normal file
32
lab4/TagRemover.cc
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
class TagRemover {
|
||||
private:
|
||||
std::string content;
|
||||
|
||||
public:
|
||||
TagRemover(std::istream& input) {
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
content += line + '\n';
|
||||
}
|
||||
}
|
||||
|
||||
void print(std::ostream& output) const {
|
||||
std::string result = std::regex_replace(content, std::regex("<[^>]*>"), "");
|
||||
result = std::regex_replace(result, std::regex("<"), "<");
|
||||
result = std::regex_replace(result, std::regex(">"), ">");
|
||||
result = std::regex_replace(result, std::regex(" "), " ");
|
||||
result = std::regex_replace(result, std::regex("&"), "&");
|
||||
|
||||
output << result;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
TagRemover tr(std::cin);
|
||||
tr.print(std::cout);
|
||||
return 0;
|
||||
}
|
76
lab4/date.cc
76
lab4/date.cc
|
@ -1,30 +1,86 @@
|
|||
#include <ctime> // time and localtime
|
||||
#include <ctime> // för tid och localtime
|
||||
#include <iomanip> // för setw och setfill
|
||||
#include <sstream> // för inputhantering
|
||||
#include "date.h"
|
||||
|
||||
int Date::daysPerMonth[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
// Konstruktor: dagens datum
|
||||
Date::Date() {
|
||||
time_t timer = time(0); // time in seconds since 1970-01-01
|
||||
tm* locTime = localtime(&timer); // broken-down time
|
||||
year = 1900 + locTime->tm_year;
|
||||
month = 1 + locTime->tm_mon;
|
||||
day = locTime->tm_mday;
|
||||
time_t timer = time(0); // tid i sekunder sedan 1970-01-01
|
||||
tm* locTime = localtime(&timer); // lokal tid
|
||||
year = 1900 + locTime->tm_year;
|
||||
month = 1 + locTime->tm_mon;
|
||||
day = locTime->tm_mday;
|
||||
}
|
||||
|
||||
Date::Date(int y, int m, int d) {}
|
||||
// Konstruktor: specifikt datum
|
||||
Date::Date(int y, int m, int d) : year(y), month(m), day(d) {}
|
||||
|
||||
// Get-funktioner
|
||||
int Date::getYear() const {
|
||||
return 0;
|
||||
return year;
|
||||
}
|
||||
|
||||
int Date::getMonth() const {
|
||||
return 0;
|
||||
return month;
|
||||
}
|
||||
|
||||
int Date::getDay() const {
|
||||
return 0;
|
||||
return day;
|
||||
}
|
||||
|
||||
// Gå till nästa dag
|
||||
void Date::next() {
|
||||
day++;
|
||||
if (day > daysPerMonth[month - 1] + (month == 2 && isLeapYear(year))) {
|
||||
day = 1;
|
||||
month++;
|
||||
if (month > 12) {
|
||||
month = 1;
|
||||
year++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kontrollera om ett år är ett skottår
|
||||
bool Date::isLeapYear(int year) {
|
||||
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
// Overloaded operator<< (output)
|
||||
std::ostream& operator<<(std::ostream& os, const Date& date) {
|
||||
os << std::setw(4) << std::setfill('0') << date.getYear() << '-'
|
||||
<< std::setw(2) << std::setfill('0') << date.getMonth() << '-'
|
||||
<< std::setw(2) << std::setfill('0') << date.getDay();
|
||||
return os;
|
||||
}
|
||||
|
||||
// Overloaded operator>> (input)
|
||||
std::istream& operator>>(std::istream& is, Date& date) {
|
||||
std::string input;
|
||||
is >> input;
|
||||
|
||||
std::istringstream iss(input);
|
||||
char dash1, dash2;
|
||||
int y, m, d;
|
||||
|
||||
if (iss >> y >> dash1 >> m >> dash2 >> d && dash1 == '-' && dash2 == '-') {
|
||||
// Validera månad och dag
|
||||
if (m >= 1 && m <= 12) {
|
||||
int maxDay = Date::daysPerMonth[m - 1];
|
||||
if (m == 2 && Date::isLeapYear(y)) {
|
||||
maxDay = 29; // Februari har 29 dagar under skottår
|
||||
}
|
||||
|
||||
if (d >= 1 && d <= maxDay) {
|
||||
date = Date(y, m, d); // Sätt datumet om det är giltigt
|
||||
return is;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ogiltig inmatning
|
||||
is.setstate(std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
|
|
28
lab4/date.h
28
lab4/date.h
|
@ -1,19 +1,27 @@
|
|||
#ifndef DATE_H
|
||||
#define DATE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class Date {
|
||||
public:
|
||||
Date(); // today's date
|
||||
Date(int y, int m, int d); // yyyy-mm-dd
|
||||
int getYear() const; // get the year
|
||||
int getMonth() const; // get the month
|
||||
int getDay() const; // get the day
|
||||
void next(); // advance to next day
|
||||
Date(); // dagens datum
|
||||
Date(int y, int m, int d); // yyyy-mm-dd
|
||||
int getYear() const; // returnerar året
|
||||
int getMonth() const; // returnerar månaden
|
||||
int getDay() const; // returnerar dagen
|
||||
void next(); // går till nästa dag
|
||||
|
||||
// Overloaded operators
|
||||
friend std::ostream& operator<<(std::ostream& os, const Date& date);
|
||||
friend std::istream& operator>>(std::istream& is, Date& date);
|
||||
|
||||
private:
|
||||
int year; // the year (four digits)
|
||||
int month; // the month (1-12)
|
||||
int day; // the day (1-..)
|
||||
static int daysPerMonth[12]; // number of days in each month
|
||||
int year; // året (fyra siffror)
|
||||
int month; // månaden (1-12)
|
||||
int day; // dagen (1-...)
|
||||
static int daysPerMonth[12]; // antal dagar i varje månad
|
||||
static bool isLeapYear(int year); // kontrollera skottår
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,64 +1,40 @@
|
|||
#include <iostream>
|
||||
#include <iomanip> // for setw and setfill
|
||||
#include "date.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::setw;
|
||||
using std::setfill;
|
||||
|
||||
/*
|
||||
* Prints the date d in the format yyyy-mm-dd. You shall replace this
|
||||
* function with an overloaded operator<<, and add an overloaded operator>>.
|
||||
*
|
||||
*/
|
||||
void print(const Date& d) {
|
||||
cout << setw(4) << setfill('0') << d.getYear() << '-';
|
||||
cout << setw(2) << setfill('0') << d.getMonth() << '-';
|
||||
cout << setw(2) << setfill('0') << d.getDay();
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Check input and output of dates. Uncomment the following when you
|
||||
// have added operator>> and operator<<.
|
||||
/*
|
||||
bool cont = true;
|
||||
while (cont) {
|
||||
cout << "Type a date: ";
|
||||
Date aDate;
|
||||
cin >> aDate;
|
||||
if (cin.eof()) {
|
||||
cont = false;
|
||||
} else if (!cin.good()) {
|
||||
cout << "Wrong input format" << endl;
|
||||
// restore stream state and ignore the rest of the line
|
||||
cin.clear();
|
||||
cin.ignore(10000, '\n');
|
||||
}
|
||||
else {
|
||||
cout << "Output: " << aDate << endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Check 'next' by creating an object describing today's date, then
|
||||
// printing dates more than a month ahead
|
||||
cout << "--- Today and more than a month ahead:" << endl;
|
||||
Date d1;
|
||||
print(d1);
|
||||
cout << endl;
|
||||
for (int i = 1; i <= 35 ; ++i) {
|
||||
d1.next();
|
||||
print(d1);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
// Check so 'next' functions correctly from one year to the next
|
||||
cout << "--- New Year's Eve and the next day:" << endl;
|
||||
Date d2(2013, 12, 31);
|
||||
print(d2);
|
||||
cout << endl;
|
||||
d2.next();
|
||||
print(d2);
|
||||
cout << endl;
|
||||
// Test input och output
|
||||
bool cont = true;
|
||||
while (cont) {
|
||||
std::cout << "Type a date: ";
|
||||
Date aDate;
|
||||
std::cin >> aDate;
|
||||
|
||||
if (std::cin.eof()) {
|
||||
cont = false;
|
||||
} else if (!std::cin.good()) {
|
||||
std::cout << "Wrong input format" << std::endl;
|
||||
std::cin.clear();
|
||||
std::cin.ignore(10000, '\n');
|
||||
} else {
|
||||
std::cout << "Output: " << aDate << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Testa 'next' med dagens datum
|
||||
std::cout << "--- Today and more than a month ahead:" << std::endl;
|
||||
Date d1;
|
||||
std::cout << d1 << std::endl;
|
||||
for (int i = 1; i <= 35; ++i) {
|
||||
d1.next();
|
||||
std::cout << d1 << std::endl;
|
||||
}
|
||||
|
||||
// Testa 'next' från nyårsafton
|
||||
std::cout << "--- New Year's Eve and the next day:" << std::endl;
|
||||
Date d2(2013, 12, 31);
|
||||
std::cout << d2 << std::endl;
|
||||
d2.next();
|
||||
std::cout << d2 << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
56
lab4/makefile
Normal file
56
lab4/makefile
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Compiler
|
||||
CXX = g++
|
||||
CXXFLAGS = -std=c++17 -Wall -Wextra -pedantic
|
||||
|
||||
# Targets
|
||||
TARGETS = TagRemover Sieve date_test toString_test string_cast_test
|
||||
|
||||
# Source files
|
||||
SRCS_TAGREMOVER = TagRemover.cc
|
||||
SRCS_SIEVE = Sieve.cc
|
||||
SRCS_DATE = date.cc
|
||||
SRCS_DATE_TEST = date_test.cc
|
||||
SRCS_TOSTRING_TEST = toString_test.cc date.cc
|
||||
SRCS_STRING_CAST_TEST = string_cast_test.cc date.cc
|
||||
|
||||
# Object files
|
||||
OBJS_TAGREMOVER = $(SRCS_TAGREMOVER:.cc=.o)
|
||||
OBJS_SIEVE = $(SRCS_SIEVE:.cc=.o)
|
||||
OBJS_DATE = $(SRCS_DATE:.cc=.o)
|
||||
OBJS_DATE_TEST = $(SRCS_DATE_TEST:.cc=.o)
|
||||
OBJS_TOSTRING_TEST = $(SRCS_TOSTRING_TEST:.cc=.o)
|
||||
OBJS_STRING_CAST_TEST = $(SRCS_STRING_CAST_TEST:.cc=.o)
|
||||
|
||||
# Default target
|
||||
all: $(TARGETS)
|
||||
|
||||
# Rule to build TagRemover
|
||||
TagRemover: $(OBJS_TAGREMOVER)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# Rule to build Sieve
|
||||
Sieve: $(OBJS_SIEVE)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# Rule to build date_test
|
||||
date_test: $(OBJS_DATE_TEST) $(OBJS_DATE)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# Rule to build toString_test
|
||||
toString_test: $(OBJS_TOSTRING_TEST)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# Rule to build string_cast_test
|
||||
string_cast_test: $(OBJS_STRING_CAST_TEST)
|
||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||
|
||||
# Rule to compile source files into object files
|
||||
%.o: %.cc
|
||||
$(CXX) $(CXXFLAGS) -c $<
|
||||
|
||||
# Clean up build artifacts
|
||||
clean:
|
||||
rm -f $(OBJS_TAGREMOVER) $(OBJS_SIEVE) $(OBJS_DATE) $(OBJS_DATE_TEST) $(OBJS_TOSTRING_TEST) $(OBJS_STRING_CAST_TEST) $(TARGETS)
|
||||
|
||||
# Phony targets
|
||||
.PHONY: all clean
|
61
lab4/reflektion.txt
Normal file
61
lab4/reflektion.txt
Normal file
|
@ -0,0 +1,61 @@
|
|||
1. In your tests, how did you test the error handling (e.g., that a wrong string_cast actually
|
||||
throws?)
|
||||
|
||||
Genom att använda en ogiltig inmatning, som "abc" eller "123abc", och verifiera att std::invalid_argument kastas korrekt.
|
||||
|
||||
|
||||
2. In TagRemover, why do you think the constructor takes an istream instead of just the
|
||||
filename?
|
||||
|
||||
Det gör klassen mer flexibel eftersom den kan arbeta med vilken ström som helst, inte bara filer. Till exempel kan den användas med std::cin eller std::stringstream.
|
||||
|
||||
|
||||
3. In TagRemover, did you process the file line by line, or did you first read the entire file?
|
||||
What are the pros and cons of these two approaches?
|
||||
|
||||
Jag läste hela filen först eftersom det är enklare att använda regex för att bearbeta hela texten på en gång.
|
||||
Fördelen är att det är mer effektivt för regex-matchning, men nackdelen är att det kräver mer minne för stora filer.
|
||||
|
||||
|
||||
4. How do you read the entire contents of an std::istream into a std::string without using
|
||||
a for or while loop?
|
||||
|
||||
Genom att använda:
|
||||
std::string content((std::istreambuf_iterator<char>(istream)), std::istreambuf_iterator<char>());
|
||||
|
||||
|
||||
5. In TagRemover, do you have duplicate code for translating the special characters? If so, how
|
||||
would you refactor your code to avoid duplicate code?
|
||||
|
||||
Ja, det finns duplicerad kod för varje specialtecken. Jag skulle använda en std::map för att lagra mönster och ersättningar och iterera genom den:
|
||||
std::map<std::string, std::string> replacements = {
|
||||
{"<", "<"}, {">", ">"}, {" ", " "}, {"&", "&"}
|
||||
};
|
||||
for (const auto& [pattern, replacement] : replacements) {
|
||||
result = std::regex_replace(result, std::regex(pattern), replacement);
|
||||
}
|
||||
|
||||
|
||||
6. How do you check if an input or output operation on a stream (e.g., operator>> or
|
||||
operator<<) has failed?
|
||||
|
||||
Genom att använda std::istream::fail() eller std::ostream::fail().
|
||||
|
||||
|
||||
7. How do you know if you have reached the end of an istream?
|
||||
|
||||
Genom att använda std::istream::eof().
|
||||
|
||||
|
||||
8. Does string_cast<int>("123kalle") return the value 123 or does it throw an exception?
|
||||
How do you implement each of those behaviours?
|
||||
|
||||
Det kastar ett undantag eftersom std::istringstream misslyckas med att konsumera hela strängen. För att tillåta delvis inläsning skulle vi behöva anpassa funktionen.
|
||||
|
||||
|
||||
9. When calling the function template toString, the template type argument is not ex-
|
||||
plicitly given in the call. For string_cast, on the other hand, you have to specify
|
||||
string_cast<int> or string_cast<Date>. What is the difference? When should explicit
|
||||
template arguments be given to function templates?
|
||||
|
||||
toString använder <<-operatören, som automatiskt identifierar typen av objekt, medan string_cast kräver en explicit typ eftersom det behöver veta vad strängen ska konverteras till.
|
14
lab4/string_cast.h
Normal file
14
lab4/string_cast.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept> // För std::invalid_argument
|
||||
|
||||
// Template function for string_cast
|
||||
template <typename T>
|
||||
T string_cast(const std::string& str) {
|
||||
std::istringstream iss(str);
|
||||
T value;
|
||||
if (!(iss >> value) || !(iss.eof())) {
|
||||
throw std::invalid_argument("Invalid conversion from string: " + str);
|
||||
}
|
||||
return value;
|
||||
}
|
29
lab4/string_cast_test.cc
Normal file
29
lab4/string_cast_test.cc
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include "date.h" // För Date-klassen
|
||||
#include "string_cast.h" // Inkludera string_cast
|
||||
|
||||
int main() {
|
||||
try {
|
||||
// Testa string_cast med int
|
||||
int i = string_cast<int>("123");
|
||||
std::cout << "Integer: " << i << std::endl;
|
||||
|
||||
// Testa string_cast med double
|
||||
double d = string_cast<double>("12.34");
|
||||
std::cout << "Double: " << d << std::endl;
|
||||
|
||||
// Testa string_cast med Date
|
||||
Date date = string_cast<Date>("2015-01-10");
|
||||
std::cout << "Date: " << date << std::endl;
|
||||
|
||||
// Testa ogiltig konvertering
|
||||
int invalid = string_cast<int>("abc");
|
||||
std::cout << "Invalid conversion: " << invalid << std::endl;
|
||||
|
||||
} catch (const std::invalid_argument& e) {
|
||||
std::cout << "Error: " << e.what() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
10
lab4/toString.h
Normal file
10
lab4/toString.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// Template function to convert an object to a string
|
||||
template <typename T>
|
||||
std::string toString(const T& obj) {
|
||||
std::ostringstream oss;
|
||||
oss << obj;
|
||||
return oss.str();
|
||||
}
|
22
lab4/toString_test.cc
Normal file
22
lab4/toString_test.cc
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <iostream>
|
||||
#include "date.h" // Inkludera Date-klassen från tidigare lösning
|
||||
#include "toString.h" // Inkludera toString-mallen
|
||||
|
||||
int main() {
|
||||
// Testa med ett primitivt datatyper
|
||||
double d = 1.234;
|
||||
int i = 42;
|
||||
std::string strDouble = toString(d);
|
||||
std::string strInt = toString(i);
|
||||
|
||||
std::cout << "Double as string: " << strDouble << std::endl;
|
||||
std::cout << "Integer as string: " << strInt << std::endl;
|
||||
|
||||
// Testa med Date-klassen
|
||||
Date today(2023, 12, 11); // Skapa ett datumobjekt
|
||||
std::string strDate = toString(today);
|
||||
|
||||
std::cout << "Date as string: " << strDate << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue